From 38e5602d783b857e91b499ff5c8b73d26cb9a2cb Mon Sep 17 00:00:00 2001 From: DavidHerran Date: Wed, 9 Sep 2026 11:06:39 -0500 Subject: [PATCH] =?UTF-8?q?feat(weights):=20RV13=20=E2=80=94=20los=2019=20?= =?UTF-8?q?estaban=20subdeclarados,=20los=2019?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Primera medicion real de los weights con frame-omni-bencher sobre el propio blob WASM. El resultado no es un ajuste fino: los 19 extrinsics de los 5 pallets custom declaraban MENOS de lo que cuestan. EL PATRON SISTEMATICO. Se costeo el storage del pallet y se olvido el que cuesta emitir un evento — System::Events, EventCount, ExecutionPhase y Number son reads y writes reales en cada extrinsic que deposita evento. Ejemplos medidos: attest_asset declaraba 4 reads / 1 write y cuesta 7/3; submit_proposal declaraba 12 us y cuesta 62; register_agent_did declaraba 3/2 y cuesta 6/4. EL PEOR, Y ES UN ERROR MIO DOCUMENTADO AL REVES. proof_size valia 0 en los 19. La cabecera de los interinos afirmaba que T::DbWeight "puebla tanto ref_time como proof_size ... cerrando el hueco". Es falso y se comprueba en la fuente: sp_weights::RuntimeDbWeight solo tiene los campos read y write, y reads(r) devuelve from_parts(read * r, 0). Los interinos arreglaron reads/writes y dejaron el proof_size exactamente donde estaba. Un proof_size en cero miente al block-builder sobre el peso PoV: es el vector de DoS que la nota decia haber cerrado. La afirmacion sobrevivio mas de un mes sin que ninguna lectura la desmintiera; la desmintio una medicion. Cada fichero generado lleva ahora un guard GENERADO desde la lista real de benchmarks que reprueba cualquier proof_size = 0 o ref_time = 0. Verificado que sabe reprobar: contra los weights anteriores se pone rojo con "`attest_asset` declara proof_size = 0". ADVERTENCIA QUE VA EN EL CODIGO, NO SOLO AQUI: son numeros de un MacBook Pro M3 Max, NO del banco de referencia BM V2. La forma (reads/writes/proof_size) no depende del hardware y es correcta; el ref_time si, y en un Pi 5 sera mayor. Un caso lo enseña solo: attest_asset BAJA de 50 a 44 us, y es el extrinsic dominado por el verify Ed25519, el mas sensible al silicio. Antes de mainnet hay que regenerar en el Pi 5 con governor y aislamiento declarados — peticion abierta a Laurha (request:66f500d54e28a80c) con el blob, el comando y la version exacta del bencher. RV12 -> RV13 (weights = consenso). TRANSACTION_VERSION intacto. 295 tests verde. Co-Authored-By: Claude Opus 5 --- .../src/weights.rs | 146 ++++- crates/origin-chain-emission/src/weights.rs | 140 +++- crates/origin-chain-fees/src/weights.rs | 140 +++- crates/origin-chain-governance/src/weights.rs | 603 +++++++++++++++--- crates/origin-chain-provenance/src/weights.rs | 249 +++++--- crates/origin-chain-runtime/src/lib.rs | 29 +- scripts/bench/regen-weights.sh | 22 +- 7 files changed, 1084 insertions(+), 245 deletions(-) diff --git a/crates/origin-chain-agent-identity/src/weights.rs b/crates/origin-chain-agent-identity/src/weights.rs index 3c65f2a..67aaa56 100644 --- a/crates/origin-chain-agent-identity/src/weights.rs +++ b/crates/origin-chain-agent-identity/src/weights.rs @@ -1,44 +1,134 @@ -//! # Weights para `pallet-agent-identity` -//! -//! ## Estado: INTERIM hand-derived (DB-aware, DoS-safe) — pendiente regeneración HW -//! -//! Ver `origin-chain-provenance/src/weights.rs` §Estado para el racional completo. -//! Números conservadores DB-aware vía `T::DbWeight` (cierran el DoS de proof_size=0 -//! del placeholder); `benchmarking.rs` es la fuente de verdad de la forma. +// SPDX-License-Identifier: Apache-2.0 +// Origin Chain — Pilar 4 · Charon +// +// ATENCION AL LEER ESTOS NUMEROS: un weight es una LATENCIA, y una latencia sin +// el hardware y el perfil de potencia que la produjeron no se puede reproducir. +// La cabecera dice HOSTNAME y CPU: creele a eso y a nada mas. Un weight medido +// en un portatil y cobrado en un Pi 5 es mispricing estructural, solo que +// invisible. Los numeros CANONICOS de mainnet salen del banco de referencia +// (Pi 5, governor y aislamiento declarados), no de la maquina de quien compila. +//! Weights AUTOGENERADOS para `origin_chain_agent_identity` — NO editar a mano. +//! +//! Regenerar: `scripts/bench/regen-weights.sh` (ver ese script para el +//! procedimiento completo y el hardware al que hay que creerle). +//! +//! GENERADO POR SUBSTRATE BENCHMARK CLI VERSION 51.0.0 +//! FECHA: 2026-09-09, STEPS: `50`, REPEAT: `20` +//! HOSTNAME: `MacBookProM3Max.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, DB CACHE: 1024 + +// Comando ejecutado: +// /Users/davidherran/.cargo/bin/frame-omni-bencher +// v1 +// benchmark +// pallet +// --runtime +// /Users/davidherran/originmetaverse/artifacts/origin-chain/origin_chain_runtime_rv12_bench.compact.compressed.wasm +// --genesis-builder-preset +// development +// --pallet +// origin_chain_agent_identity +// --extrinsic +// +// --steps +// 50 +// --repeat +// 20 +// --template +// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/scripts/bench/origin-weights-template.hbs +// --header +// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/scripts/bench/HEADER.txt +// --output +// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/crates/origin-chain-agent-identity/src/weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -#![allow(clippy::unnecessary_cast)] +#![allow(missing_docs)] use core::marker::PhantomData; use frame_support::{traits::Get, weights::constants::RocksDbWeight, weights::Weight}; -/// Trait de weights para los extrinsics de `pallet-agent-identity`. +/// Trait de weights para los extrinsics de `origin_chain_agent_identity`. pub trait WeightInfo { - /// Peso de `register_agent_did` — 2-3 reads + verify Ed25519 + derive_did + 2 writes. - fn register_agent_did() -> Weight; + /// Peso de `register_agent_did` — MEDIDO sobre el WASM, no estimado a mano. + fn register_agent_did() -> Weight; } -/// Weights parametrizados por el `DbWeight` del runtime. +/// Weights parametrizados por el `DbWeight` real del runtime. pub struct SubstrateWeight(PhantomData); - impl WeightInfo for SubstrateWeight { - fn register_agent_did() -> Weight { - // Compute: Ed25519 verify (dominante) + derive_did (BLAKE3) + decode + - // build BoundedVec agent_chain. Storage: contains_key(Identities) + - // contains_key(DidToAccount) + block_number = 3 reads; insert(Identities) - // + insert(DidToAccount) = 2 writes. - Weight::from_parts(50_000_000, 0) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } + /// Storage: `AgentIdentity::Identities` (r:1 w:1) + /// Proof: `AgentIdentity::Identities` (`max_values`: None, `max_size`: Some(475), added: 2950, mode: `MaxEncodedLen`) + /// Storage: `AgentIdentity::DidToAccount` (r:1 w:1) + /// Proof: `AgentIdentity::DidToAccount` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn register_agent_did() -> Weight { + // Proof size en bytes: + // Medido: `25` + // Estimado: `3940` + // Tiempo minimo de ejecucion: 41_000_000 picosegundos. + Weight::from_parts(43_000_000, 0) + .saturating_add(Weight::from_parts(0, 3940)) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } } -/// Impl no-op para mocks / tests. +/// Impl para mocks y tests — `RocksDbWeight` directo, sin necesitar `T`. impl WeightInfo for () { - fn register_agent_did() -> Weight { - Weight::from_parts(50_000_000, 0) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } + fn register_agent_did() -> Weight { + Weight::from_parts(43_000_000, 0) + .saturating_add(Weight::from_parts(0, 3940)) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } +} + +#[cfg(test)] +mod guard { + use super::*; + + /// NINGUN EXTRINSIC PUEDE DECLARAR `proof_size = 0`. + /// + /// El `proof_size` es lo que el block-builder usa para no pasarse del limite + /// de PoV. Un cero no dice «este extrinsic no toca storage»: dice «miento + /// sobre lo que va a ocupar la prueba», y con eso entra en un bloque mucho + /// mas de lo que cabe. + /// + /// El test nace de un error propio y de la peor clase: la cabecera de los + /// weights interinos afirmaba que `T::DbWeight` «puebla tanto ref_time como + /// proof_size … cerrando el hueco». Es falso y se comprueba en la fuente — + /// `sp_weights::RuntimeDbWeight` solo tiene los campos `read` y `write`, y + /// `reads(r)` devuelve `Weight::from_parts(read * r, 0)`. Los interinos + /// arreglaron reads/writes y dejaron el proof_size donde estaba: en 0. La + /// afirmacion de haberlo cerrado sobrevivio mas de un mes sin que ninguna + /// lectura la desmintiera; la desmintio una medicion. + /// + /// Esta lista la GENERA la plantilla a partir de los benchmarks reales, asi + /// que no puede quedarse corta cuando se anada un extrinsic nuevo. + #[test] + fn ningun_weight_declara_proof_size_cero() { + let casos: &[(&str, Weight)] = &[ + ("register_agent_did", <() as WeightInfo>::register_agent_did()), + ]; + for (nombre, w) in casos { + assert!( + w.proof_size() > 0, + "`{nombre}` declara proof_size = 0: miente al block-builder sobre el peso PoV" + ); + assert!( + w.ref_time() > 0, + "`{nombre}` declara ref_time = 0: el extrinsic saldria gratis" + ); + } + } } diff --git a/crates/origin-chain-emission/src/weights.rs b/crates/origin-chain-emission/src/weights.rs index 2c7bd04..626a4d1 100644 --- a/crates/origin-chain-emission/src/weights.rs +++ b/crates/origin-chain-emission/src/weights.rs @@ -1,40 +1,132 @@ -//! # Weights para `pallet-origin-emission` -//! -//! ## Estado: INTERIM hand-derived (DB-aware) — pendiente regeneración HW -//! -//! Ver `origin-chain-provenance/src/weights.rs` §Estado. Nota: `set_emission_paused` -//! ya era DB-aware antes de esta migración (usaba `T::DbWeight::get().reads_writes(1,1)` -//! directo — el ÚNICO extrinsic del chain que nunca fue DoS-prone). Aquí se mueve -//! ese mismo cálculo detrás del trait `WeightInfo` por consistencia con los demás -//! pallets + para exponerlo a `benchmark pallet`. `benchmarking.rs` es la fuente -//! de verdad de la forma. +// SPDX-License-Identifier: Apache-2.0 +// Origin Chain — Pilar 4 · Charon +// +// ATENCION AL LEER ESTOS NUMEROS: un weight es una LATENCIA, y una latencia sin +// el hardware y el perfil de potencia que la produjeron no se puede reproducir. +// La cabecera dice HOSTNAME y CPU: creele a eso y a nada mas. Un weight medido +// en un portatil y cobrado en un Pi 5 es mispricing estructural, solo que +// invisible. Los numeros CANONICOS de mainnet salen del banco de referencia +// (Pi 5, governor y aislamiento declarados), no de la maquina de quien compila. +//! Weights AUTOGENERADOS para `origin_chain_emission` — NO editar a mano. +//! +//! Regenerar: `scripts/bench/regen-weights.sh` (ver ese script para el +//! procedimiento completo y el hardware al que hay que creerle). +//! +//! GENERADO POR SUBSTRATE BENCHMARK CLI VERSION 51.0.0 +//! FECHA: 2026-09-09, STEPS: `50`, REPEAT: `20` +//! HOSTNAME: `MacBookProM3Max.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, DB CACHE: 1024 + +// Comando ejecutado: +// /Users/davidherran/.cargo/bin/frame-omni-bencher +// v1 +// benchmark +// pallet +// --runtime +// /Users/davidherran/originmetaverse/artifacts/origin-chain/origin_chain_runtime_rv12_bench.compact.compressed.wasm +// --genesis-builder-preset +// development +// --pallet +// origin_chain_emission +// --extrinsic +// +// --steps +// 50 +// --repeat +// 20 +// --template +// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/scripts/bench/origin-weights-template.hbs +// --header +// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/scripts/bench/HEADER.txt +// --output +// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/crates/origin-chain-emission/src/weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -#![allow(clippy::unnecessary_cast)] +#![allow(missing_docs)] use core::marker::PhantomData; use frame_support::{traits::Get, weights::constants::RocksDbWeight, weights::Weight}; -/// Trait de weights para los extrinsics de `pallet-origin-emission`. +/// Trait de weights para los extrinsics de `origin_chain_emission`. pub trait WeightInfo { - /// Peso de `set_emission_paused` (Root) — 1 read (guard no-op) + 1 write. - fn set_emission_paused() -> Weight; + /// Peso de `set_emission_paused` — MEDIDO sobre el WASM, no estimado a mano. + fn set_emission_paused() -> Weight; } -/// Weights parametrizados por el `DbWeight` del runtime. +/// Weights parametrizados por el `DbWeight` real del runtime. pub struct SubstrateWeight(PhantomData); - impl WeightInfo for SubstrateWeight { - fn set_emission_paused() -> Weight { - // ensure_root + get(EmissionPaused) [guard no-op] + put(EmissionPaused). - T::DbWeight::get().reads_writes(1, 1) - } + /// Storage: `Emission::EmissionPaused` (r:1 w:1) + /// Proof: `Emission::EmissionPaused` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_emission_paused() -> Weight { + // Proof size en bytes: + // Medido: `61` + // Estimado: `1546` + // Tiempo minimo de ejecucion: 7_000_000 picosegundos. + Weight::from_parts(8_000_000, 0) + .saturating_add(Weight::from_parts(0, 1546)) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } } -/// Impl no-op para mocks / tests. +/// Impl para mocks y tests — `RocksDbWeight` directo, sin necesitar `T`. impl WeightInfo for () { - fn set_emission_paused() -> Weight { - RocksDbWeight::get().reads_writes(1, 1) - } + fn set_emission_paused() -> Weight { + Weight::from_parts(8_000_000, 0) + .saturating_add(Weight::from_parts(0, 1546)) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } +} + +#[cfg(test)] +mod guard { + use super::*; + + /// NINGUN EXTRINSIC PUEDE DECLARAR `proof_size = 0`. + /// + /// El `proof_size` es lo que el block-builder usa para no pasarse del limite + /// de PoV. Un cero no dice «este extrinsic no toca storage»: dice «miento + /// sobre lo que va a ocupar la prueba», y con eso entra en un bloque mucho + /// mas de lo que cabe. + /// + /// El test nace de un error propio y de la peor clase: la cabecera de los + /// weights interinos afirmaba que `T::DbWeight` «puebla tanto ref_time como + /// proof_size … cerrando el hueco». Es falso y se comprueba en la fuente — + /// `sp_weights::RuntimeDbWeight` solo tiene los campos `read` y `write`, y + /// `reads(r)` devuelve `Weight::from_parts(read * r, 0)`. Los interinos + /// arreglaron reads/writes y dejaron el proof_size donde estaba: en 0. La + /// afirmacion de haberlo cerrado sobrevivio mas de un mes sin que ninguna + /// lectura la desmintiera; la desmintio una medicion. + /// + /// Esta lista la GENERA la plantilla a partir de los benchmarks reales, asi + /// que no puede quedarse corta cuando se anada un extrinsic nuevo. + #[test] + fn ningun_weight_declara_proof_size_cero() { + let casos: &[(&str, Weight)] = &[ + ("set_emission_paused", <() as WeightInfo>::set_emission_paused()), + ]; + for (nombre, w) in casos { + assert!( + w.proof_size() > 0, + "`{nombre}` declara proof_size = 0: miente al block-builder sobre el peso PoV" + ); + assert!( + w.ref_time() > 0, + "`{nombre}` declara ref_time = 0: el extrinsic saldria gratis" + ); + } + } } diff --git a/crates/origin-chain-fees/src/weights.rs b/crates/origin-chain-fees/src/weights.rs index 432e89a..ac154b2 100644 --- a/crates/origin-chain-fees/src/weights.rs +++ b/crates/origin-chain-fees/src/weights.rs @@ -1,40 +1,132 @@ -//! # Weights para `pallet-origin-fees` -//! -//! ## Estado: INTERIM hand-derived (DB-aware, DoS-safe) — pendiente regeneración HW -//! -//! Ver `origin-chain-provenance/src/weights.rs` §Estado para el racional completo. -//! Resumen: números conservadores derivados a mano (no autogenerados por CLI — -//! gated por sc-service/omni-bencher+WASM), pero **DB-aware** vía `T::DbWeight` -//! → pueblan ref_time + proof_size por read/write real, cerrando el DoS de los -//! placeholders `Weight::from_parts(10_000, 0)` (proof_size = 0, sin contar DB). -//! `benchmarking.rs` es la fuente de verdad de la forma. +// SPDX-License-Identifier: Apache-2.0 +// Origin Chain — Pilar 4 · Charon +// +// ATENCION AL LEER ESTOS NUMEROS: un weight es una LATENCIA, y una latencia sin +// el hardware y el perfil de potencia que la produjeron no se puede reproducir. +// La cabecera dice HOSTNAME y CPU: creele a eso y a nada mas. Un weight medido +// en un portatil y cobrado en un Pi 5 es mispricing estructural, solo que +// invisible. Los numeros CANONICOS de mainnet salen del banco de referencia +// (Pi 5, governor y aislamiento declarados), no de la maquina de quien compila. +//! Weights AUTOGENERADOS para `origin_chain_fees` — NO editar a mano. +//! +//! Regenerar: `scripts/bench/regen-weights.sh` (ver ese script para el +//! procedimiento completo y el hardware al que hay que creerle). +//! +//! GENERADO POR SUBSTRATE BENCHMARK CLI VERSION 51.0.0 +//! FECHA: 2026-09-09, STEPS: `50`, REPEAT: `20` +//! HOSTNAME: `MacBookProM3Max.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, DB CACHE: 1024 + +// Comando ejecutado: +// /Users/davidherran/.cargo/bin/frame-omni-bencher +// v1 +// benchmark +// pallet +// --runtime +// /Users/davidherran/originmetaverse/artifacts/origin-chain/origin_chain_runtime_rv12_bench.compact.compressed.wasm +// --genesis-builder-preset +// development +// --pallet +// origin_chain_fees +// --extrinsic +// +// --steps +// 50 +// --repeat +// 20 +// --template +// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/scripts/bench/origin-weights-template.hbs +// --header +// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/scripts/bench/HEADER.txt +// --output +// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/crates/origin-chain-fees/src/weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -#![allow(clippy::unnecessary_cast)] +#![allow(missing_docs)] use core::marker::PhantomData; use frame_support::{traits::Get, weights::constants::RocksDbWeight, weights::Weight}; -/// Trait de weights para los extrinsics de `pallet-origin-fees`. +/// Trait de weights para los extrinsics de `origin_chain_fees`. pub trait WeightInfo { - /// Peso de `set_tier_profile` (Root) — 1 write (TierProfiles). - fn set_tier_profile() -> Weight; + /// Peso de `set_tier_profile` — MEDIDO sobre el WASM, no estimado a mano. + fn set_tier_profile() -> Weight; } -/// Weights parametrizados por el `DbWeight` del runtime. +/// Weights parametrizados por el `DbWeight` real del runtime. pub struct SubstrateWeight(PhantomData); - impl WeightInfo for SubstrateWeight { - fn set_tier_profile() -> Weight { - // ensure_root (in-memory) + insert(TierProfiles) = 1 write. - Weight::from_parts(8_000_000, 0).saturating_add(T::DbWeight::get().writes(1_u64)) - } + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Fees::TierProfiles` (r:0 w:1) + /// Proof: `Fees::TierProfiles` (`max_values`: None, `max_size`: Some(50), added: 2525, mode: `MaxEncodedLen`) + fn set_tier_profile() -> Weight { + // Proof size en bytes: + // Medido: `19` + // Estimado: `1504` + // Tiempo minimo de ejecucion: 6_000_000 picosegundos. + Weight::from_parts(7_000_000, 0) + .saturating_add(Weight::from_parts(0, 1504)) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } } -/// Impl no-op para mocks / tests. +/// Impl para mocks y tests — `RocksDbWeight` directo, sin necesitar `T`. impl WeightInfo for () { - fn set_tier_profile() -> Weight { - Weight::from_parts(8_000_000, 0).saturating_add(RocksDbWeight::get().writes(1_u64)) - } + fn set_tier_profile() -> Weight { + Weight::from_parts(7_000_000, 0) + .saturating_add(Weight::from_parts(0, 1504)) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } +} + +#[cfg(test)] +mod guard { + use super::*; + + /// NINGUN EXTRINSIC PUEDE DECLARAR `proof_size = 0`. + /// + /// El `proof_size` es lo que el block-builder usa para no pasarse del limite + /// de PoV. Un cero no dice «este extrinsic no toca storage»: dice «miento + /// sobre lo que va a ocupar la prueba», y con eso entra en un bloque mucho + /// mas de lo que cabe. + /// + /// El test nace de un error propio y de la peor clase: la cabecera de los + /// weights interinos afirmaba que `T::DbWeight` «puebla tanto ref_time como + /// proof_size … cerrando el hueco». Es falso y se comprueba en la fuente — + /// `sp_weights::RuntimeDbWeight` solo tiene los campos `read` y `write`, y + /// `reads(r)` devuelve `Weight::from_parts(read * r, 0)`. Los interinos + /// arreglaron reads/writes y dejaron el proof_size donde estaba: en 0. La + /// afirmacion de haberlo cerrado sobrevivio mas de un mes sin que ninguna + /// lectura la desmintiera; la desmintio una medicion. + /// + /// Esta lista la GENERA la plantilla a partir de los benchmarks reales, asi + /// que no puede quedarse corta cuando se anada un extrinsic nuevo. + #[test] + fn ningun_weight_declara_proof_size_cero() { + let casos: &[(&str, Weight)] = &[ + ("set_tier_profile", <() as WeightInfo>::set_tier_profile()), + ]; + for (nombre, w) in casos { + assert!( + w.proof_size() > 0, + "`{nombre}` declara proof_size = 0: miente al block-builder sobre el peso PoV" + ); + assert!( + w.ref_time() > 0, + "`{nombre}` declara ref_time = 0: el extrinsic saldria gratis" + ); + } + } } diff --git a/crates/origin-chain-governance/src/weights.rs b/crates/origin-chain-governance/src/weights.rs index fb43b04..1e9d157 100644 --- a/crates/origin-chain-governance/src/weights.rs +++ b/crates/origin-chain-governance/src/weights.rs @@ -1,103 +1,532 @@ -//! # Weights para `pallet-origin-governance` -//! -//! ## Estado: INTERIM hand-derived (DB-aware, DoS-safe) — pendiente regeneración HW -//! -//! Ver `origin-chain-provenance/src/weights.rs` §Estado para el racional completo. -//! Los 13 extrinsics tenían `Weight::from_parts(10_000, 0)` (proof_size=0, sin -//! contar DB) → DoS. Aquí cada uno se cuesta con `T::DbWeight` sobre los reads/writes -//! REALES contados del código (incluyendo los `iter_prefix`/`clear_prefix` acotados -//! por el council ≤ 7). `benchmarking.rs` es la fuente de verdad de la forma. +// SPDX-License-Identifier: Apache-2.0 +// Origin Chain — Pilar 4 · Charon +// +// ATENCION AL LEER ESTOS NUMEROS: un weight es una LATENCIA, y una latencia sin +// el hardware y el perfil de potencia que la produjeron no se puede reproducir. +// La cabecera dice HOSTNAME y CPU: creele a eso y a nada mas. Un weight medido +// en un portatil y cobrado en un Pi 5 es mispricing estructural, solo que +// invisible. Los numeros CANONICOS de mainnet salen del banco de referencia +// (Pi 5, governor y aislamiento declarados), no de la maquina de quien compila. +//! Weights AUTOGENERADOS para `origin_chain_governance` — NO editar a mano. +//! +//! Regenerar: `scripts/bench/regen-weights.sh` (ver ese script para el +//! procedimiento completo y el hardware al que hay que creerle). +//! +//! GENERADO POR SUBSTRATE BENCHMARK CLI VERSION 51.0.0 +//! FECHA: 2026-09-09, STEPS: `50`, REPEAT: `20` +//! HOSTNAME: `MacBookProM3Max.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, DB CACHE: 1024 + +// Comando ejecutado: +// /Users/davidherran/.cargo/bin/frame-omni-bencher +// v1 +// benchmark +// pallet +// --runtime +// /Users/davidherran/originmetaverse/artifacts/origin-chain/origin_chain_runtime_rv12_bench.compact.compressed.wasm +// --genesis-builder-preset +// development +// --pallet +// origin_chain_governance +// --extrinsic +// +// --steps +// 50 +// --repeat +// 20 +// --template +// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/scripts/bench/origin-weights-template.hbs +// --header +// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/scripts/bench/HEADER.txt +// --output +// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/crates/origin-chain-governance/src/weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -#![allow(clippy::unnecessary_cast)] +#![allow(missing_docs)] use core::marker::PhantomData; use frame_support::{traits::Get, weights::constants::RocksDbWeight, weights::Weight}; -/// Compute floor conservador para la lógica de cada extrinsic (hashing blake2, -/// aritmética de umbrales, build de structs). Los que hashean content/proposal id -/// (submit_*, endorse) llevan un poco más vía el propio conteo de reads. -const COMPUTE: u64 = 12_000_000; - -/// Trait de weights para los 13 extrinsics de `pallet-origin-governance`. +/// Trait de weights para los extrinsics de `origin_chain_governance`. pub trait WeightInfo { - /// `submit_proposal` — contains_key + bond transfer + 2 inserts. - fn submit_proposal() -> Weight; - /// `cast_vote` — advisor/proposal/vote reads + 2 inserts. - fn cast_vote() -> Weight; - /// `finalize_proposal` — proposal read/write + release bond. - fn finalize_proposal() -> Weight; - /// `add_council_member` — size/dup reads + 2 writes. - fn add_council_member() -> Weight; - /// `remove_council_member` — exists read + remove + size write. - fn remove_council_member() -> Weight; - /// `veto_proposal` — council iter (≤7) + threshold flip path. - fn veto_proposal() -> Weight; - /// `mark_as_advisor` — 1 read + 1 write. - fn mark_as_advisor() -> Weight; - /// `unmark_as_advisor` — 1 read + 1 write. - fn unmark_as_advisor() -> Weight; - /// `override_council_veto` — proposal/veto/advisor reads + vote inserts. - fn override_council_veto() -> Weight; - /// `submit_emergency_proposal` — endorsement iter (≤7) + bond + clear_prefix. - fn submit_emergency_proposal() -> Weight; - /// `treasury_disbursement` — proposal read + single-use + transfer. - fn treasury_disbursement() -> Weight; - /// `treasury_deposit` — transfer only. - fn treasury_deposit() -> Weight; - /// `endorse_emergency_proposal` — council iter (≤7) + insert. - fn endorse_emergency_proposal() -> Weight; + /// Peso de `submit_proposal` — MEDIDO sobre el WASM, no estimado a mano. + fn submit_proposal() -> Weight; + /// Peso de `cast_vote` — MEDIDO sobre el WASM, no estimado a mano. + fn cast_vote() -> Weight; + /// Peso de `finalize_proposal` — MEDIDO sobre el WASM, no estimado a mano. + fn finalize_proposal() -> Weight; + /// Peso de `add_council_member` — MEDIDO sobre el WASM, no estimado a mano. + fn add_council_member() -> Weight; + /// Peso de `remove_council_member` — MEDIDO sobre el WASM, no estimado a mano. + fn remove_council_member() -> Weight; + /// Peso de `veto_proposal` — MEDIDO sobre el WASM, no estimado a mano. + fn veto_proposal() -> Weight; + /// Peso de `mark_as_advisor` — MEDIDO sobre el WASM, no estimado a mano. + fn mark_as_advisor() -> Weight; + /// Peso de `unmark_as_advisor` — MEDIDO sobre el WASM, no estimado a mano. + fn unmark_as_advisor() -> Weight; + /// Peso de `override_council_veto` — MEDIDO sobre el WASM, no estimado a mano. + fn override_council_veto() -> Weight; + /// Peso de `submit_emergency_proposal` — MEDIDO sobre el WASM, no estimado a mano. + fn submit_emergency_proposal() -> Weight; + /// Peso de `treasury_disbursement` — MEDIDO sobre el WASM, no estimado a mano. + fn treasury_disbursement() -> Weight; + /// Peso de `treasury_deposit` — MEDIDO sobre el WASM, no estimado a mano. + fn treasury_deposit() -> Weight; + /// Peso de `endorse_emergency_proposal` — MEDIDO sobre el WASM, no estimado a mano. + fn endorse_emergency_proposal() -> Weight; } -macro_rules! w { - ($r:expr, $w:expr) => { - Weight::from_parts(COMPUTE, 0) - .saturating_add(T::DbWeight::get().reads($r as u64)) - .saturating_add(T::DbWeight::get().writes($w as u64)) - }; -} - -/// Weights parametrizados por el `DbWeight` del runtime. +/// Weights parametrizados por el `DbWeight` real del runtime. pub struct SubstrateWeight(PhantomData); - impl WeightInfo for SubstrateWeight { - fn submit_proposal() -> Weight { w!(3, 4) } - fn cast_vote() -> Weight { w!(4, 2) } - fn finalize_proposal() -> Weight { w!(3, 4) } - fn add_council_member() -> Weight { w!(3, 2) } - fn remove_council_member() -> Weight { w!(2, 2) } - fn veto_proposal() -> Weight { w!(10, 4) } - fn mark_as_advisor() -> Weight { w!(1, 1) } - fn unmark_as_advisor() -> Weight { w!(1, 1) } - fn override_council_veto() -> Weight { w!(5, 3) } - fn submit_emergency_proposal() -> Weight { w!(12, 11) } - fn treasury_disbursement() -> Weight { w!(4, 3) } - fn treasury_deposit() -> Weight { w!(2, 2) } - fn endorse_emergency_proposal() -> Weight { w!(10, 1) } + /// Storage: `Governance::Proposals` (r:1 w:1) + /// Proof: `Governance::Proposals` (`max_values`: None, `max_size`: Some(257), added: 2732, mode: `MaxEncodedLen`) + /// Storage: `Balances::TotalIssuance` (r:1 w:0) + /// Proof: `Balances::TotalIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Governance::ProposalBond` (r:0 w:1) + /// Proof: `Governance::ProposalBond` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `MaxEncodedLen`) + fn submit_proposal() -> Weight { + // Proof size en bytes: + // Medido: `107` + // Estimado: `3722` + // Tiempo minimo de ejecucion: 46_000_000 picosegundos. + Weight::from_parts(46_000_000, 0) + .saturating_add(Weight::from_parts(0, 3722)) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `Governance::AdvisorFlags` (r:1 w:0) + /// Proof: `Governance::AdvisorFlags` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Governance::Proposals` (r:1 w:1) + /// Proof: `Governance::Proposals` (`max_values`: None, `max_size`: Some(257), added: 2732, mode: `MaxEncodedLen`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Governance::Votes` (r:1 w:1) + /// Proof: `Governance::Votes` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn cast_vote() -> Weight { + // Proof size en bytes: + // Medido: `310` + // Estimado: `3722` + // Tiempo minimo de ejecucion: 16_000_000 picosegundos. + Weight::from_parts(18_000_000, 0) + .saturating_add(Weight::from_parts(0, 3722)) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Governance::Proposals` (r:1 w:1) + /// Proof: `Governance::Proposals` (`max_values`: None, `max_size`: Some(257), added: 2732, mode: `MaxEncodedLen`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Governance::ProposalBond` (r:1 w:0) + /// Proof: `Governance::ProposalBond` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn finalize_proposal() -> Weight { + // Proof size en bytes: + // Medido: `310` + // Estimado: `3722` + // Tiempo minimo de ejecucion: 13_000_000 picosegundos. + Weight::from_parts(14_000_000, 0) + .saturating_add(Weight::from_parts(0, 3722)) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Governance::CouncilSize` (r:1 w:1) + /// Proof: `Governance::CouncilSize` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Governance::Council` (r:1 w:1) + /// Proof: `Governance::Council` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn add_council_member() -> Weight { + // Proof size en bytes: + // Medido: `25` + // Estimado: `3554` + // Tiempo minimo de ejecucion: 10_000_000 picosegundos. + Weight::from_parts(11_000_000, 0) + .saturating_add(Weight::from_parts(0, 3554)) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Governance::Council` (r:1 w:1) + /// Proof: `Governance::Council` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Governance::CouncilSize` (r:1 w:1) + /// Proof: `Governance::CouncilSize` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn remove_council_member() -> Weight { + // Proof size en bytes: + // Medido: `153` + // Estimado: `3554` + // Tiempo minimo de ejecucion: 11_000_000 picosegundos. + Weight::from_parts(12_000_000, 0) + .saturating_add(Weight::from_parts(0, 3554)) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Governance::Council` (r:1 w:0) + /// Proof: `Governance::Council` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Governance::Proposals` (r:1 w:1) + /// Proof: `Governance::Proposals` (`max_values`: None, `max_size`: Some(257), added: 2732, mode: `MaxEncodedLen`) + /// Storage: `Governance::CouncilSize` (r:1 w:0) + /// Proof: `Governance::CouncilSize` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Governance::VetoVotes` (r:2 w:1) + /// Proof: `Governance::VetoVotes` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `MaxEncodedLen`) + /// Storage: `Governance::ProposalBond` (r:1 w:0) + /// Proof: `Governance::ProposalBond` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `MaxEncodedLen`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Governance::VetoRejected` (r:0 w:1) + /// Proof: `Governance::VetoRejected` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Governance::VetoCount` (r:0 w:1) + /// Proof: `Governance::VetoCount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn veto_proposal() -> Weight { + // Proof size en bytes: + // Medido: `435` + // Estimado: `6132` + // Tiempo minimo de ejecucion: 28_000_000 picosegundos. + Weight::from_parts(30_000_000, 0) + .saturating_add(Weight::from_parts(0, 6132)) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: `Governance::AdvisorFlags` (r:1 w:1) + /// Proof: `Governance::AdvisorFlags` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn mark_as_advisor() -> Weight { + // Proof size en bytes: + // Medido: `25` + // Estimado: `3513` + // Tiempo minimo de ejecucion: 9_000_000 picosegundos. + Weight::from_parts(10_000_000, 0) + .saturating_add(Weight::from_parts(0, 3513)) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Governance::AdvisorFlags` (r:1 w:1) + /// Proof: `Governance::AdvisorFlags` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn unmark_as_advisor() -> Weight { + // Proof size en bytes: + // Medido: `98` + // Estimado: `3513` + // Tiempo minimo de ejecucion: 10_000_000 picosegundos. + Weight::from_parts(10_000_000, 0) + .saturating_add(Weight::from_parts(0, 3513)) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Governance::Proposals` (r:1 w:0) + /// Proof: `Governance::Proposals` (`max_values`: None, `max_size`: Some(257), added: 2732, mode: `MaxEncodedLen`) + /// Storage: `Governance::VetoRejected` (r:1 w:0) + /// Proof: `Governance::VetoRejected` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Governance::AdvisorFlags` (r:1 w:0) + /// Proof: `Governance::AdvisorFlags` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Governance::OverrideVotes` (r:1 w:1) + /// Proof: `Governance::OverrideVotes` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) + /// Storage: `Governance::OverrideStakeTotal` (r:1 w:1) + /// Proof: `Governance::OverrideStakeTotal` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + fn override_council_veto() -> Weight { + // Proof size en bytes: + // Medido: `361` + // Estimado: `3722` + // Tiempo minimo de ejecucion: 16_000_000 picosegundos. + Weight::from_parts(16_000_000, 0) + .saturating_add(Weight::from_parts(0, 3722)) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Governance::Council` (r:1 w:0) + /// Proof: `Governance::Council` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Governance::CouncilSize` (r:1 w:0) + /// Proof: `Governance::CouncilSize` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Governance::EmergencyEndorsements` (r:2 w:1) + /// Proof: `Governance::EmergencyEndorsements` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `MaxEncodedLen`) + /// Storage: `Governance::Proposals` (r:1 w:1) + /// Proof: `Governance::Proposals` (`max_values`: None, `max_size`: Some(257), added: 2732, mode: `MaxEncodedLen`) + /// Storage: `Balances::TotalIssuance` (r:1 w:0) + /// Proof: `Balances::TotalIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Governance::ProposalBond` (r:0 w:1) + /// Proof: `Governance::ProposalBond` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `MaxEncodedLen`) + fn submit_emergency_proposal() -> Weight { + // Proof size en bytes: + // Medido: `353` + // Estimado: `6132` + // Tiempo minimo de ejecucion: 60_000_000 picosegundos. + Weight::from_parts(61_000_000, 0) + .saturating_add(Weight::from_parts(0, 6132)) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: `Governance::Proposals` (r:1 w:0) + /// Proof: `Governance::Proposals` (`max_values`: None, `max_size`: Some(257), added: 2732, mode: `MaxEncodedLen`) + /// Storage: `Governance::Disbursed` (r:1 w:1) + /// Proof: `Governance::Disbursed` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Balances::TotalIssuance` (r:1 w:0) + /// Proof: `Balances::TotalIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn treasury_disbursement() -> Weight { + // Proof size en bytes: + // Medido: `494` + // Estimado: `6196` + // Tiempo minimo de ejecucion: 51_000_000 picosegundos. + Weight::from_parts(52_000_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `Balances::TotalIssuance` (r:1 w:0) + /// Proof: `Balances::TotalIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn treasury_deposit() -> Weight { + // Proof size en bytes: + // Medido: `101` + // Estimado: `3593` + // Tiempo minimo de ejecucion: 38_000_000 picosegundos. + Weight::from_parts(42_000_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Governance::Council` (r:1 w:0) + /// Proof: `Governance::Council` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Governance::EmergencyEndorsements` (r:2 w:1) + /// Proof: `Governance::EmergencyEndorsements` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `MaxEncodedLen`) + /// Storage: `Governance::CouncilSize` (r:1 w:0) + /// Proof: `Governance::CouncilSize` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn endorse_emergency_proposal() -> Weight { + // Proof size en bytes: + // Medido: `153` + // Estimado: `6132` + // Tiempo minimo de ejecucion: 20_000_000 picosegundos. + Weight::from_parts(21_000_000, 0) + .saturating_add(Weight::from_parts(0, 6132)) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } } -macro_rules! wnop { - ($r:expr, $w:expr) => { - Weight::from_parts(COMPUTE, 0) - .saturating_add(RocksDbWeight::get().reads($r as u64)) - .saturating_add(RocksDbWeight::get().writes($w as u64)) - }; -} - -/// Impl no-op para mocks / tests. +/// Impl para mocks y tests — `RocksDbWeight` directo, sin necesitar `T`. impl WeightInfo for () { - fn submit_proposal() -> Weight { wnop!(3, 4) } - fn cast_vote() -> Weight { wnop!(4, 2) } - fn finalize_proposal() -> Weight { wnop!(3, 4) } - fn add_council_member() -> Weight { wnop!(3, 2) } - fn remove_council_member() -> Weight { wnop!(2, 2) } - fn veto_proposal() -> Weight { wnop!(10, 4) } - fn mark_as_advisor() -> Weight { wnop!(1, 1) } - fn unmark_as_advisor() -> Weight { wnop!(1, 1) } - fn override_council_veto() -> Weight { wnop!(5, 3) } - fn submit_emergency_proposal() -> Weight { wnop!(12, 11) } - fn treasury_disbursement() -> Weight { wnop!(4, 3) } - fn treasury_deposit() -> Weight { wnop!(2, 2) } - fn endorse_emergency_proposal() -> Weight { wnop!(10, 1) } + fn submit_proposal() -> Weight { + Weight::from_parts(46_000_000, 0) + .saturating_add(Weight::from_parts(0, 3722)) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + fn cast_vote() -> Weight { + Weight::from_parts(18_000_000, 0) + .saturating_add(Weight::from_parts(0, 3722)) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + fn finalize_proposal() -> Weight { + Weight::from_parts(14_000_000, 0) + .saturating_add(Weight::from_parts(0, 3722)) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + fn add_council_member() -> Weight { + Weight::from_parts(11_000_000, 0) + .saturating_add(Weight::from_parts(0, 3554)) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + fn remove_council_member() -> Weight { + Weight::from_parts(12_000_000, 0) + .saturating_add(Weight::from_parts(0, 3554)) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + fn veto_proposal() -> Weight { + Weight::from_parts(30_000_000, 0) + .saturating_add(Weight::from_parts(0, 6132)) + .saturating_add(RocksDbWeight::get().reads(10_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + fn mark_as_advisor() -> Weight { + Weight::from_parts(10_000_000, 0) + .saturating_add(Weight::from_parts(0, 3513)) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + fn unmark_as_advisor() -> Weight { + Weight::from_parts(10_000_000, 0) + .saturating_add(Weight::from_parts(0, 3513)) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + fn override_council_veto() -> Weight { + Weight::from_parts(16_000_000, 0) + .saturating_add(Weight::from_parts(0, 3722)) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + fn submit_emergency_proposal() -> Weight { + Weight::from_parts(61_000_000, 0) + .saturating_add(Weight::from_parts(0, 6132)) + .saturating_add(RocksDbWeight::get().reads(11_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + fn treasury_disbursement() -> Weight { + Weight::from_parts(52_000_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(RocksDbWeight::get().reads(9_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + fn treasury_deposit() -> Weight { + Weight::from_parts(42_000_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + fn endorse_emergency_proposal() -> Weight { + Weight::from_parts(21_000_000, 0) + .saturating_add(Weight::from_parts(0, 6132)) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } +} + +#[cfg(test)] +mod guard { + use super::*; + + /// NINGUN EXTRINSIC PUEDE DECLARAR `proof_size = 0`. + /// + /// El `proof_size` es lo que el block-builder usa para no pasarse del limite + /// de PoV. Un cero no dice «este extrinsic no toca storage»: dice «miento + /// sobre lo que va a ocupar la prueba», y con eso entra en un bloque mucho + /// mas de lo que cabe. + /// + /// El test nace de un error propio y de la peor clase: la cabecera de los + /// weights interinos afirmaba que `T::DbWeight` «puebla tanto ref_time como + /// proof_size … cerrando el hueco». Es falso y se comprueba en la fuente — + /// `sp_weights::RuntimeDbWeight` solo tiene los campos `read` y `write`, y + /// `reads(r)` devuelve `Weight::from_parts(read * r, 0)`. Los interinos + /// arreglaron reads/writes y dejaron el proof_size donde estaba: en 0. La + /// afirmacion de haberlo cerrado sobrevivio mas de un mes sin que ninguna + /// lectura la desmintiera; la desmintio una medicion. + /// + /// Esta lista la GENERA la plantilla a partir de los benchmarks reales, asi + /// que no puede quedarse corta cuando se anada un extrinsic nuevo. + #[test] + fn ningun_weight_declara_proof_size_cero() { + let casos: &[(&str, Weight)] = &[ + ("submit_proposal", <() as WeightInfo>::submit_proposal()), + ("cast_vote", <() as WeightInfo>::cast_vote()), + ("finalize_proposal", <() as WeightInfo>::finalize_proposal()), + ("add_council_member", <() as WeightInfo>::add_council_member()), + ("remove_council_member", <() as WeightInfo>::remove_council_member()), + ("veto_proposal", <() as WeightInfo>::veto_proposal()), + ("mark_as_advisor", <() as WeightInfo>::mark_as_advisor()), + ("unmark_as_advisor", <() as WeightInfo>::unmark_as_advisor()), + ("override_council_veto", <() as WeightInfo>::override_council_veto()), + ("submit_emergency_proposal", <() as WeightInfo>::submit_emergency_proposal()), + ("treasury_disbursement", <() as WeightInfo>::treasury_disbursement()), + ("treasury_deposit", <() as WeightInfo>::treasury_deposit()), + ("endorse_emergency_proposal", <() as WeightInfo>::endorse_emergency_proposal()), + ]; + for (nombre, w) in casos { + assert!( + w.proof_size() > 0, + "`{nombre}` declara proof_size = 0: miente al block-builder sobre el peso PoV" + ); + assert!( + w.ref_time() > 0, + "`{nombre}` declara ref_time = 0: el extrinsic saldria gratis" + ); + } + } } diff --git a/crates/origin-chain-provenance/src/weights.rs b/crates/origin-chain-provenance/src/weights.rs index 2884d90..eb6c39f 100644 --- a/crates/origin-chain-provenance/src/weights.rs +++ b/crates/origin-chain-provenance/src/weights.rs @@ -1,87 +1,194 @@ -//! # Weights para `pallet-origin-provenance` -//! -//! ## Estado: INTERIM hand-derived (DB-aware, DoS-safe) — pendiente regeneración HW -//! -//! Estos weights son **derivados a mano de forma conservadora**, NO autogenerados -//! por `frame-benchmarking-cli` sobre hardware de referencia todavía. La razón es -//! infraestructural, no de diseño: generar los números canónicos requiere ejecutar -//! el loop `benchmark pallet`, que necesita **o** el node `sc-service` real -//! (bloqueado por el mismatch de API sc-*/sp-consensus del tag stable2509-3, ver -//! `main.rs` §BLOQUEO) **o** `frame-omni-bencher` sobre el `WASM_BINARY` (gated tras -//! la feature `wasm-build`). Cuando cualquiera de los dos aterrice (VPS / HW de -//! referencia Pi5), regenerar es mecánico: los benchmarks de `benchmarking.rs` son -//! la **fuente de verdad de la forma** y sobrescribirán estos números. -//! -//! ## Por qué esto ya es una mejora de seguridad REAL -//! -//! Los placeholders anteriores eran `Weight::from_parts(10_000, 0)`: **proof_size = 0 -//! y sin contabilizar reads/writes de DB**. Eso es un vector de DoS — un atacante -//! llama extrinsics que tocan varias entradas de storage pagando casi nada, y el -//! `proof_size = 0` miente al block-builder sobre el peso PoV. Estos weights usan -//! `T::DbWeight` (RocksDbWeight en el runtime), que puebla **tanto ref_time como -//! proof_size** por cada read/write real contado del código — cerrando el hueco. -//! -//! El componente `from_parts(N, 0)` fijo cubre el compute (decode postcard, verify -//! Ed25519, hashing) con holgura conservadora; el `DbWeight` cubre el storage. +// SPDX-License-Identifier: Apache-2.0 +// Origin Chain — Pilar 4 · Charon +// +// ATENCION AL LEER ESTOS NUMEROS: un weight es una LATENCIA, y una latencia sin +// el hardware y el perfil de potencia que la produjeron no se puede reproducir. +// La cabecera dice HOSTNAME y CPU: creele a eso y a nada mas. Un weight medido +// en un portatil y cobrado en un Pi 5 es mispricing estructural, solo que +// invisible. Los numeros CANONICOS de mainnet salen del banco de referencia +// (Pi 5, governor y aislamiento declarados), no de la maquina de quien compila. +//! Weights AUTOGENERADOS para `origin_chain_provenance` — NO editar a mano. +//! +//! Regenerar: `scripts/bench/regen-weights.sh` (ver ese script para el +//! procedimiento completo y el hardware al que hay que creerle). +//! +//! GENERADO POR SUBSTRATE BENCHMARK CLI VERSION 51.0.0 +//! FECHA: 2026-09-09, STEPS: `50`, REPEAT: `20` +//! HOSTNAME: `MacBookProM3Max.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, DB CACHE: 1024 + +// Comando ejecutado: +// /Users/davidherran/.cargo/bin/frame-omni-bencher +// v1 +// benchmark +// pallet +// --runtime +// /Users/davidherran/originmetaverse/artifacts/origin-chain/origin_chain_runtime_rv12_bench.compact.compressed.wasm +// --genesis-builder-preset +// development +// --pallet +// origin_chain_provenance +// --extrinsic +// +// --steps +// 50 +// --repeat +// 20 +// --template +// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/scripts/bench/origin-weights-template.hbs +// --header +// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/scripts/bench/HEADER.txt +// --output +// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/crates/origin-chain-provenance/src/weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -#![allow(clippy::unnecessary_cast)] +#![allow(missing_docs)] use core::marker::PhantomData; use frame_support::{traits::Get, weights::constants::RocksDbWeight, weights::Weight}; -/// Trait de weights para los extrinsics de `pallet-origin-provenance`. +/// Trait de weights para los extrinsics de `origin_chain_provenance`. pub trait WeightInfo { - /// Peso de `attest_asset` — decode postcard + 3-4 reads + verify Ed25519 + 1 write. - fn attest_asset() -> Weight; - /// Peso de `register_validator` (Root) — 1 write. - fn register_validator() -> Weight; - /// Peso de `revoke_validator` (Root) — 1 write (remove). - fn revoke_validator() -> Weight; + /// Peso de `attest_asset` — MEDIDO sobre el WASM, no estimado a mano. + fn attest_asset() -> Weight; + /// Peso de `register_validator` — MEDIDO sobre el WASM, no estimado a mano. + fn register_validator() -> Weight; + /// Peso de `revoke_validator` — MEDIDO sobre el WASM, no estimado a mano. + fn revoke_validator() -> Weight; } -/// Weights para `pallet-origin-provenance` parametrizados por el `DbWeight` del runtime. -/// -/// Se usa en el runtime como `SubstrateWeight` → los reads/writes se cuestan -/// con el `RocksDbWeight` real de la cadena, no con constantes hardcodeadas. +/// Weights parametrizados por el `DbWeight` real del runtime. pub struct SubstrateWeight(PhantomData); - impl WeightInfo for SubstrateWeight { - fn attest_asset() -> Weight { - // Compute conservador: decode postcard (~115 bytes) + Ed25519 verify - // (dominante, ~50µs en HW de referencia) + BLAKE-hashing del dominio. - // Storage: contains_key(Attestations) + get(AuthorizedValidators) + - // block_hash(0) + block_number = 4 reads; insert(Attestations) = 1 write. - Weight::from_parts(50_000_000, 0) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - - fn register_validator() -> Weight { - // ensure_root (in-memory) + insert(AuthorizedValidators) = 1 write. - Weight::from_parts(8_000_000, 0).saturating_add(T::DbWeight::get().writes(1_u64)) - } - - fn revoke_validator() -> Weight { - // ensure_root (in-memory) + remove(AuthorizedValidators) = 1 write. - Weight::from_parts(8_000_000, 0).saturating_add(T::DbWeight::get().writes(1_u64)) - } + /// Storage: `Provenance::Attestations` (r:1 w:1) + /// Proof: `Provenance::Attestations` (`max_values`: None, `max_size`: Some(505), added: 2980, mode: `MaxEncodedLen`) + /// Storage: `Provenance::AuthorizedValidators` (r:1 w:0) + /// Proof: `Provenance::AuthorizedValidators` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn attest_asset() -> Weight { + // Proof size en bytes: + // Medido: `153` + // Estimado: `3970` + // Tiempo minimo de ejecucion: 43_000_000 picosegundos. + Weight::from_parts(44_000_000, 0) + .saturating_add(Weight::from_parts(0, 3970)) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Provenance::AuthorizedValidators` (r:0 w:1) + /// Proof: `Provenance::AuthorizedValidators` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + fn register_validator() -> Weight { + // Proof size en bytes: + // Medido: `19` + // Estimado: `1504` + // Tiempo minimo de ejecucion: 6_000_000 picosegundos. + Weight::from_parts(7_000_000, 0) + .saturating_add(Weight::from_parts(0, 1504)) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `System::Number` (r:1 w:0) + /// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::ExecutionPhase` (r:1 w:0) + /// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `System::EventCount` (r:1 w:1) + /// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Events` (r:1 w:1) + /// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Provenance::AuthorizedValidators` (r:0 w:1) + /// Proof: `Provenance::AuthorizedValidators` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + fn revoke_validator() -> Weight { + // Proof size en bytes: + // Medido: `19` + // Estimado: `1504` + // Tiempo minimo de ejecucion: 6_000_000 picosegundos. + Weight::from_parts(7_000_000, 0) + .saturating_add(Weight::from_parts(0, 1504)) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } } -/// Impl no-op para mocks / tests — usa `RocksDbWeight` directo (no requiere `T`). +/// Impl para mocks y tests — `RocksDbWeight` directo, sin necesitar `T`. impl WeightInfo for () { - fn attest_asset() -> Weight { - Weight::from_parts(50_000_000, 0) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - - fn register_validator() -> Weight { - Weight::from_parts(8_000_000, 0).saturating_add(RocksDbWeight::get().writes(1_u64)) - } - - fn revoke_validator() -> Weight { - Weight::from_parts(8_000_000, 0).saturating_add(RocksDbWeight::get().writes(1_u64)) - } + fn attest_asset() -> Weight { + Weight::from_parts(44_000_000, 0) + .saturating_add(Weight::from_parts(0, 3970)) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + fn register_validator() -> Weight { + Weight::from_parts(7_000_000, 0) + .saturating_add(Weight::from_parts(0, 1504)) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + fn revoke_validator() -> Weight { + Weight::from_parts(7_000_000, 0) + .saturating_add(Weight::from_parts(0, 1504)) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } +} + +#[cfg(test)] +mod guard { + use super::*; + + /// NINGUN EXTRINSIC PUEDE DECLARAR `proof_size = 0`. + /// + /// El `proof_size` es lo que el block-builder usa para no pasarse del limite + /// de PoV. Un cero no dice «este extrinsic no toca storage»: dice «miento + /// sobre lo que va a ocupar la prueba», y con eso entra en un bloque mucho + /// mas de lo que cabe. + /// + /// El test nace de un error propio y de la peor clase: la cabecera de los + /// weights interinos afirmaba que `T::DbWeight` «puebla tanto ref_time como + /// proof_size … cerrando el hueco». Es falso y se comprueba en la fuente — + /// `sp_weights::RuntimeDbWeight` solo tiene los campos `read` y `write`, y + /// `reads(r)` devuelve `Weight::from_parts(read * r, 0)`. Los interinos + /// arreglaron reads/writes y dejaron el proof_size donde estaba: en 0. La + /// afirmacion de haberlo cerrado sobrevivio mas de un mes sin que ninguna + /// lectura la desmintiera; la desmintio una medicion. + /// + /// Esta lista la GENERA la plantilla a partir de los benchmarks reales, asi + /// que no puede quedarse corta cuando se anada un extrinsic nuevo. + #[test] + fn ningun_weight_declara_proof_size_cero() { + let casos: &[(&str, Weight)] = &[ + ("attest_asset", <() as WeightInfo>::attest_asset()), + ("register_validator", <() as WeightInfo>::register_validator()), + ("revoke_validator", <() as WeightInfo>::revoke_validator()), + ]; + for (nombre, w) in casos { + assert!( + w.proof_size() > 0, + "`{nombre}` declara proof_size = 0: miente al block-builder sobre el peso PoV" + ); + assert!( + w.ref_time() > 0, + "`{nombre}` declara ref_time = 0: el extrinsic saldria gratis" + ); + } + } } diff --git a/crates/origin-chain-runtime/src/lib.rs b/crates/origin-chain-runtime/src/lib.rs index d497862..d4fee20 100644 --- a/crates/origin-chain-runtime/src/lib.rs +++ b/crates/origin-chain-runtime/src/lib.rs @@ -315,6 +315,31 @@ pub const IMPL_NAME: &str = borrowed_str(&VERSION.impl_name); /// lo llama `los_tres_presets_construyen_estado`, con contrafactual verificado. /// Nada de esto cambia una transicion de estado de la cadena viva (no hay cadena /// viva): el bump es por higiene de blob y de metadata. TRANSACTION_VERSION intacto. +/// +/// **v13 (los weights dejan de ser estimados y pasan a ser medidos)**: los 19 +/// extrinsics de los 5 pallets custom cambian de weights INTERIM hand-derived a +/// weights MEDIDOS con `frame-omni-bencher` sobre el propio blob WASM. Los +/// weights son consenso-relevantes ⇒ spec bump obligatorio. Lo que la medicion +/// destapo: **los 19 estaban subdeclarados, los 19.** El patron sistematico era +/// el mismo — se costeo el storage del pallet y se olvido el que cuesta emitir +/// un evento (`System::Events`, `EventCount`, `ExecutionPhase`, `Number`), que +/// son reads y writes reales en cada extrinsic que deposita evento. Y el peor: +/// **`proof_size` valia 0 en los 19**, que es exactamente el agujero que la +/// cabecera de los interinos afirmaba haber cerrado — falso, porque +/// `sp_weights::RuntimeDbWeight` solo tiene `read` y `write` y su `reads(r)` +/// devuelve `from_parts(read * r, 0)`. Un `proof_size` en cero miente al +/// block-builder sobre el peso PoV. Ahora cada fichero generado lleva un guard +/// que reprueba cualquier cero. +/// +/// ⚠️ **NUMEROS DE MAQUINA DE DESARROLLO, NO CANONICOS.** Estan medidos en un +/// MacBook Pro M3 Max, no en el banco de referencia BM V2 (Pi 5). La FORMA +/// (reads / writes / proof_size) no depende del hardware y es correcta; el +/// `ref_time` SI depende, y en un Pi 5 sera bastante mayor. Un caso lo enseña +/// solo: `attest_asset` BAJA de 50 a 44 µs, y es justo el extrinsic dominado +/// por el verify Ed25519 — el mas sensible al silicio. Antes de mainnet hay que +/// correr `scripts/bench/regen-weights.sh` en el Pi 5 con governor y aislamiento +/// declarados (peticion abierta a Laurha, `request:66f500d54e28a80c`). +/// TRANSACTION_VERSION intacto: ninguna firma de extrinsic cambia. pub const RUNTIME_VERSION: u32 = VERSION.spec_version; /// Canonical authoring version per Substrate semver canonical. @@ -961,7 +986,7 @@ pub const VERSION: sp_version::RuntimeVersion = sp_version::RuntimeVersion { spec_name: alloc::borrow::Cow::Borrowed("origin-chain"), impl_name: alloc::borrow::Cow::Borrowed("origin-chain-charon"), authoring_version: 1, - spec_version: 12, + spec_version: 13, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -997,7 +1022,7 @@ mod tests { /// mismo commit en que la version subio a 12. #[test] fn spec_version_vigente_y_transaction_version_intacta() { - assert_eq!(RUNTIME_VERSION, 12); + assert_eq!(RUNTIME_VERSION, 13); assert_eq!(TRANSACTION_VERSION, 1); } diff --git a/scripts/bench/regen-weights.sh b/scripts/bench/regen-weights.sh index 24fd6bd..0edf3b5 100755 --- a/scripts/bench/regen-weights.sh +++ b/scripts/bench/regen-weights.sh @@ -58,14 +58,18 @@ fi echo "blob: $( (shasum -a 256 "$WASM" 2>/dev/null || sha256sum "$WASM") | cut -d' ' -f1)" echo "═══ 2/2 midiendo (steps=$STEPS repeat=$REPEAT) ═══" -declare -A DEST=( - [origin_chain_provenance]=crates/origin-chain-provenance/src/weights.rs - [origin_chain_agent_identity]=crates/origin-chain-agent-identity/src/weights.rs - [origin_chain_fees]=crates/origin-chain-fees/src/weights.rs - [origin_chain_emission]=crates/origin-chain-emission/src/weights.rs - [origin_chain_governance]=crates/origin-chain-governance/src/weights.rs -) -for p in "${!DEST[@]}"; do +PARES=" +origin_chain_provenance:crates/origin-chain-provenance/src/weights.rs +origin_chain_agent_identity:crates/origin-chain-agent-identity/src/weights.rs +origin_chain_fees:crates/origin-chain-fees/src/weights.rs +origin_chain_emission:crates/origin-chain-emission/src/weights.rs +origin_chain_governance:crates/origin-chain-governance/src/weights.rs +" +# Lista plana y no array asociativo a proposito: el bash por defecto de macOS +# es el 3.2, que no tiene `declare -A`, y con `set -u` falla con un +# «unbound variable» que no se parece en nada a la causa. +echo "$PARES" | while IFS=: read -r p dest; do + [ -n "$p" ] || continue echo "── $p" "$BENCHER" v1 benchmark pallet \ --runtime "$WASM" --genesis-builder-preset development \ @@ -73,7 +77,7 @@ for p in "${!DEST[@]}"; do --steps "$STEPS" --repeat "$REPEAT" \ --template "$ROOT/scripts/bench/origin-weights-template.hbs" \ --header "$ROOT/scripts/bench/HEADER.txt" \ - --output "$ROOT/${DEST[$p]}" + --output "$ROOT/$dest" done echo "═══ listo — ahora: cargo test --workspace ═══"