feat(gobierno): spec 18 (RV17), quorum del voto ordinario y pago del tesoro atado a la propuesta

Gobierno (origin-chain-governance):
- El voto ordinario exige un quorum de Aye, el 10 % de PILAR_4 §6.6. Se fija AL CREAR la
  propuesta (VoteQuorumOf) y se consume al decidirla: un set_code no mueve la meta de un
  voto abierto. Cuenta solo el Aye: con el Nay, un voto en contra podria aprobar; con la
  abstencion, el mismo OGC inflaria el quorum de muchas propuestas.
- Un override del veto tiene que alcanzar ese quorum y superar el Nay original, las dos
  condiciones del voto ordinario. Sin ellas, vetar abarataba una aprobacion (dos bloqueantes
  de las revisiones adversariales).
- submit_treasury_proposal (call 16) fija destinatario y monto (TreasuryActions), y
  treasury_disbursement solo paga exactamente eso, una vez. Rechaza montos bajo el deposito
  existencial y como destinatario la propia tesoreria o la cuenta-bond.
- Sin entrada en VoteQuorumOf no hay quorum: la emergencia (que nunca lleva accion de
  tesoro) y lo creado antes de RV17, que se abrio y voto sin quorum.

Runtime: los dos quorums son el 10 % de la emision VIGENTE, redondeado hacia arriba y nunca
por debajo del bond (DiezPorCientoDeLaEmision). Con 100M fijos, en la testnet de la casa
(100M emitidos, todos de Alice) nada se habria aprobado nunca; en mainnet sigue siendo ~100M.
Spec 18, transaction_version 1: todo lo nuevo es aditivo, sin migracion.

Node: pasa a opaque::Block. Decodificaba los extrinsics con tipos nativos y rechazaba en el
pool la llamada que anadia el set_code (1040, el mismo error que una llamada inexistente).
Los bytes y los hashes no cambian: el binario nuevo sincronizo desde cero los 39 273 bloques
de la testnet de la casa con los mismos hashes en 8 alturas. El RPC sirve los extrinsics en hex.

Pesos: seis extrinsics cambiaron de codigo y se midieron en la Pi 5 (smoke declarado: 5
procesos limpios, sin CI en ningun segundo, maximo de los 5). Los otros once siguen siendo los
certificados por Laurha. Se descarto una medida contaminada: su muestreador no veia los tests
de la CI.

Pruebas:
- 363 tests verdes en el workspace.
- 24 contrafactuales, los 24 en rojo.
- Ensayo en la rp1 sobre una cadena con el codigo vivo de spec 17: upgrade a 18 y E2E
  firmando como un wallet (scripts/e2e/rv17_tesoro.py).
- Ejemplo firmar_como_wallet con tesoro, pagar, votar, depositar y finalizar; los eventos
  llevan su fase.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
CharonandClaude Opus 5.5 committed 2026-10-28 21:55:24 -05:00
1 parent abe680e853
commit b6d05eaf45
14 files changed
+1368 -155

No files matched your search

+98 -32
View File
@@ -21,6 +21,25 @@
// TIEMPO DE EJECUCIÓN sale de 2,5 a 3,9 veces el del Mac M3 Max (~6 veces en los que verifican
// Ed25519). Lo COBRADO sube menos, entre +4 % y +56 %, porque lecturas y escrituras de storage
// (RocksDbWeight) no cambian y pesan más que la ejecución (revisión adversarial, 25-oct).
//
// SPEC 18 (RV17): SEIS de estos pesos NO son de Laurha. Los midió Charon en la misma Pi el
// 2026-10-28, 21:49-21:52, porque su código cambió: `submit_proposal`, `submit_treasury_proposal`,
// `finalize_proposal`, `finalize_override`, `veto_proposal` y `treasury_disbursement`.
// Es un SMOKE DECLARADO, no un certificado:
// governor ondemand (no performance) a 2,4 GHz, núcleo 3 por taskset y SIN aislar,
// throttled 0x0, 48-64 °C.
// 5 procesos LIMPIOS: ningún job de la CI vivo en ningún segundo de cada ventana (cualquier
// proceso de gitea-runner salvo el daemon), y 30 s de calma antes de cada uno.
// frame-omni-bencher 0.15.0 · wasm sha256 539d7bf4…9311eb9 (spec 18, RV17) · steps 50 ·
// repeat 20 · máximo de los 5 (max-de-n.py).
// Evidencia en la rp1: ~/charon/bench-spec18/v2 (limpios/, perfil-v3.csv, limpio.log,
// SHA256SUMS-limpio).
// Se descartó una medida anterior: su muestreador sólo contaba `rustc` y no veía los binarios de
// test de la CI. Un proceso salió 10 veces más lento y el máximo lo habría cobrado.
// Calibración: sobre los 11 que no cambian, este smoke da 0,75-1,25 veces lo certificado (el
// ruido entre procesos que midió Laurha). Esos 11 se quedan con lo de Laurha. Las lecturas, las
// escrituras y el proof de los 17 coinciden con el bench del Mac sobre el mismo wasm. Laurha
// puede certificar los 6 en su banco y sustituirlos.
//! Weights AUTOGENERADOS para `origin_chain_governance` — NO editar a mano.
//!
@@ -102,6 +121,8 @@ pub trait WeightInfo {
fn uphold_council_veto() -> Weight;
/// Peso de `finalize_override` — MEDIDO sobre el WASM, no estimado a mano.
fn finalize_override() -> Weight;
/// Peso de `submit_treasury_proposal` — MEDIDO sobre el WASM, no estimado a mano.
fn submit_treasury_proposal() -> Weight;
}
/// Weights parametrizados por el `DbWeight` real del runtime.
@@ -121,17 +142,19 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// 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::VoteQuorumOf` (r:0 w:1)
/// Proof: `Governance::VoteQuorumOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`)
/// 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: `108`
// Estimado: `3722`
// Tiempo minimo de ejecucion: 116_074_000 picosegundos.
Weight::from_parts(122_075_000, 0)
// Tiempo minimo de ejecucion: 120_389_000 picosegundos.
Weight::from_parts(124_315_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))
.saturating_add(T::DbWeight::get().writes(6_u64))
}
/// Storage: `Governance::AdvisorFlags` (r:1 w:0)
/// Proof: `Governance::AdvisorFlags` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
@@ -167,6 +190,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// 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::VoteQuorumOf` (r:1 w:1)
/// Proof: `Governance::VoteQuorumOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`)
/// Storage: `Governance::ProposalBond` (r:1 w:1)
/// Proof: `Governance::ProposalBond` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `MaxEncodedLen`)
/// Storage: `Balances::TotalIssuance` (r:1 w:0)
@@ -181,13 +206,13 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn finalize_proposal() -> Weight {
// Proof size en bytes:
// Medido: `615`
// Medido: `701`
// Estimado: `6196`
// Tiempo minimo de ejecucion: 132_890_000 picosegundos.
Weight::from_parts(146_594_000, 0)
// Tiempo minimo de ejecucion: 143_834_000 picosegundos.
Weight::from_parts(147_649_000, 0)
.saturating_add(Weight::from_parts(0, 6196))
.saturating_add(T::DbWeight::get().reads(9_u64))
.saturating_add(T::DbWeight::get().writes(6_u64))
.saturating_add(T::DbWeight::get().reads(10_u64))
.saturating_add(T::DbWeight::get().writes(7_u64))
}
/// Storage: `Governance::CouncilSize` (r:1 w:1)
/// Proof: `Governance::CouncilSize` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -243,10 +268,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Proof: `Governance::CouncilSize` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
/// Storage: `Governance::VetoVotes` (r:6 w:1)
/// Proof: `Governance::VetoVotes` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `MaxEncodedLen`)
/// Storage: `Governance::ProposalBond` (r:1 w:1)
/// Proof: `Governance::ProposalBond` (`max_values`: None, `max_size`: Some(96), added: 2571, 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: `Governance::ProposalBond` (r:1 w:1)
/// Proof: `Governance::ProposalBond` (`max_values`: None, `max_size`: Some(96), added: 2571, 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::ExecutionPhase` (r:1 w:0)
@@ -267,8 +292,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Proof size en bytes:
// Medido: `1441`
// Estimado: `16416`
// Tiempo minimo de ejecucion: 250_076_000 picosegundos.
Weight::from_parts(266_779_000, 0)
// Tiempo minimo de ejecucion: 250_427_000 picosegundos.
Weight::from_parts(279_612_000, 0)
.saturating_add(Weight::from_parts(0, 16416))
.saturating_add(T::DbWeight::get().reads(21_u64))
.saturating_add(T::DbWeight::get().writes(11_u64))
@@ -387,6 +412,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// 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: `Governance::TreasuryActions` (r:1 w:0)
/// Proof: `Governance::TreasuryActions` (`max_values`: None, `max_size`: Some(96), added: 2571, 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)
@@ -401,12 +428,12 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn treasury_disbursement() -> Weight {
// Proof size en bytes:
// Medido: `495`
// Medido: `615`
// Estimado: `6196`
// Tiempo minimo de ejecucion: 126_964_000 picosegundos.
Weight::from_parts(138_038_000, 0)
// Tiempo minimo de ejecucion: 133_815_000 picosegundos.
Weight::from_parts(144_130_000, 0)
.saturating_add(Weight::from_parts(0, 6196))
.saturating_add(T::DbWeight::get().reads(9_u64))
.saturating_add(T::DbWeight::get().reads(10_u64))
.saturating_add(T::DbWeight::get().writes(5_u64))
}
/// Storage: `Balances::TotalIssuance` (r:1 w:0)
@@ -533,6 +560,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Proof: `Governance::UpholdStakeTotal` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`)
/// Storage: `Governance::OverrideQuorum` (r:1 w:1)
/// Proof: `Governance::OverrideQuorum` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`)
/// Storage: `Governance::VoteQuorumOf` (r:1 w:1)
/// Proof: `Governance::VoteQuorumOf` (`max_values`: None, `max_size`: Some(64), added: 2539, 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)
@@ -541,23 +570,53 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn finalize_override() -> Weight {
// Proof size en bytes:
// Medido: `637`
// Medido: `723`
// Estimado: `3722`
// Tiempo minimo de ejecucion: 73_297_000 picosegundos.
Weight::from_parts(78_037_000, 0)
// Tiempo minimo de ejecucion: 83_908_000 picosegundos.
Weight::from_parts(86_407_000, 0)
.saturating_add(Weight::from_parts(0, 3722))
.saturating_add(T::DbWeight::get().reads(10_u64))
.saturating_add(T::DbWeight::get().writes(5_u64))
.saturating_add(T::DbWeight::get().reads(11_u64))
.saturating_add(T::DbWeight::get().writes(6_u64))
}
/// 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::VoteQuorumOf` (r:0 w:1)
/// Proof: `Governance::VoteQuorumOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`)
/// Storage: `Governance::TreasuryActions` (r:0 w:1)
/// Proof: `Governance::TreasuryActions` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `MaxEncodedLen`)
/// Storage: `Governance::ProposalBond` (r:0 w:1)
/// Proof: `Governance::ProposalBond` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `MaxEncodedLen`)
fn submit_treasury_proposal() -> Weight {
// Proof size en bytes:
// Medido: `108`
// Estimado: `3722`
// Tiempo minimo de ejecucion: 128_000_000 picosegundos.
Weight::from_parts(132_148_000, 0)
.saturating_add(Weight::from_parts(0, 3722))
.saturating_add(T::DbWeight::get().reads(7_u64))
.saturating_add(T::DbWeight::get().writes(7_u64))
}
}
/// Impl para mocks y tests — `RocksDbWeight` directo, sin necesitar `T`.
impl WeightInfo for () {
fn submit_proposal() -> Weight {
Weight::from_parts(122_075_000, 0)
Weight::from_parts(124_315_000, 0)
.saturating_add(Weight::from_parts(0, 3722))
.saturating_add(RocksDbWeight::get().reads(7_u64))
.saturating_add(RocksDbWeight::get().writes(5_u64))
.saturating_add(RocksDbWeight::get().writes(6_u64))
}
fn cast_vote() -> Weight {
Weight::from_parts(127_723_000, 0)
@@ -566,10 +625,10 @@ impl WeightInfo for () {
.saturating_add(RocksDbWeight::get().writes(6_u64))
}
fn finalize_proposal() -> Weight {
Weight::from_parts(146_594_000, 0)
Weight::from_parts(147_649_000, 0)
.saturating_add(Weight::from_parts(0, 6196))
.saturating_add(RocksDbWeight::get().reads(9_u64))
.saturating_add(RocksDbWeight::get().writes(6_u64))
.saturating_add(RocksDbWeight::get().reads(10_u64))
.saturating_add(RocksDbWeight::get().writes(7_u64))
}
fn add_council_member() -> Weight {
Weight::from_parts(39_278_000, 0)
@@ -584,7 +643,7 @@ impl WeightInfo for () {
.saturating_add(RocksDbWeight::get().writes(4_u64))
}
fn veto_proposal() -> Weight {
Weight::from_parts(266_779_000, 0)
Weight::from_parts(279_612_000, 0)
.saturating_add(Weight::from_parts(0, 16416))
.saturating_add(RocksDbWeight::get().reads(21_u64))
.saturating_add(RocksDbWeight::get().writes(11_u64))
@@ -614,9 +673,9 @@ impl WeightInfo for () {
.saturating_add(RocksDbWeight::get().writes(6_u64))
}
fn treasury_disbursement() -> Weight {
Weight::from_parts(138_038_000, 0)
Weight::from_parts(144_130_000, 0)
.saturating_add(Weight::from_parts(0, 6196))
.saturating_add(RocksDbWeight::get().reads(9_u64))
.saturating_add(RocksDbWeight::get().reads(10_u64))
.saturating_add(RocksDbWeight::get().writes(5_u64))
}
fn treasury_deposit() -> Weight {
@@ -644,10 +703,16 @@ impl WeightInfo for () {
.saturating_add(RocksDbWeight::get().writes(6_u64))
}
fn finalize_override() -> Weight {
Weight::from_parts(78_037_000, 0)
Weight::from_parts(86_407_000, 0)
.saturating_add(Weight::from_parts(0, 3722))
.saturating_add(RocksDbWeight::get().reads(10_u64))
.saturating_add(RocksDbWeight::get().writes(5_u64))
.saturating_add(RocksDbWeight::get().reads(11_u64))
.saturating_add(RocksDbWeight::get().writes(6_u64))
}
fn submit_treasury_proposal() -> Weight {
Weight::from_parts(132_148_000, 0)
.saturating_add(Weight::from_parts(0, 3722))
.saturating_add(RocksDbWeight::get().reads(7_u64))
.saturating_add(RocksDbWeight::get().writes(7_u64))
}
}
@@ -692,6 +757,7 @@ mod guard {
("unlock_vote_funds", <() as WeightInfo>::unlock_vote_funds()),
("uphold_council_veto", <() as WeightInfo>::uphold_council_veto()),
("finalize_override", <() as WeightInfo>::finalize_override()),
("submit_treasury_proposal", <() as WeightInfo>::submit_treasury_proposal()),
];
for (nombre, w) in casos {
assert!(