feat(governance): RV15 — el peso de un voto sale del saldo, y la revision adversaria tumbo la primera version
Cierra L-10. cast_vote y override_council_veto sumaban el stake_weight que
DECLARABA el votante (hueco medido por Palace el 2026-09-06; test en rojo
publicado en d37a278). Ahora:
- El peso no puede superar el OGC LIBRE de la cuenta, y ese OGC queda
congelado (fungible freeze, FreezeReason::GovernanceVote) mientras el voto
pueda cambiar un resultado: hasta end_block en un voto normal y hasta el
cierre de la ventana en un override. El mismo OGC puede respaldar votos en
propuestas distintas (se solapan, como en Polkadot), pero no puede salir de
la cuenta: se cierra votar, transferir y votar otra vez desde otra cuenta.
- Un respaldo POR VOTO (VoteBacking: propuesta, tipo, importe, hasta), no uno
por cuenta. El freeze es siempre el maximo de los votos VIVOS; los vencidos
se descartan solos al votar o desbloquear. MaxActiveVotes = 32 en el runtime.
- unlock_vote_funds(who) lo puede llamar CUALQUIERA, como el unlock de
conviction-voting: quien vota con todo su saldo no puede pagar la comision de
su propio desbloqueo. Libera solo lo que ya no respalda un voto vivo.
- El override tiene ventana: 14 dias desde el veto que ALCANZA el umbral
(antes estaba abierto para siempre). Sin ventana registrada, falla cerrado.
- voting_period_blocks tiene tope: 28 dias (MAX_VOTING_PERIOD_BLOCKS).
- VoteFundsUnlocked va al FINAL del enum de eventos: no desplaza indices SCALE.
- spec_version 14 -> 15; transaction_version sigue en 1.
La revision adversaria (4 lentes independientes sobre la primera version)
encontro tres fallos serios, y los tres eran mios:
1. El lock unico por cuenta (max importe, max bloque) mas un periodo de voto
sin tope congelaba OGC PARA SIEMPRE: un voto de 1 unidad en una propuesta de
periodo u64::MAX arrastraba el voto mayor de la cuenta hasta ese bloque, y ni
el veto lo liberaba. Lo demostraron tres lentes por separado. Cura: respaldo
por voto + tope de periodo.
2. Un lock vencido y no desbloqueado revivia con el siguiente voto pequeno.
3. Votar con todo el saldo dejaba la cuenta sin poder pagar la comision del
unlock, y solo ella podia desbloquearse. Cura: unlock por terceros.
Y seis mutaciones sobrevivian a mi suite, entre ellas congelar el peso del
voto actual en vez del maximo (el propio ataque que el test decia cubrir).
Certificacion: 17 contrafactuales, TODOS en rojo con su pieza quitada
(freeze = peso actual, sin exigir saldo, reducible_balance, total_balance,
unlock en until, sin podar vencidos, ventana desde start_block, ventana 0,
peso 0 con thaw, evento released=0, unlock todo o nada, sin tope de periodo,
unlock solo propio, override hasta end_block, veto sin ventana, sin freeze, y
MaxFreezes=0 en el runtime). Cada test lleva control positivo. Test nuevo con
la configuracion REAL del runtime (preset local_testnet): el voto congela en
pallet-balances, lo congelado no sale, y un tercero lo libera al vencer.
Benchmarks en el PEOR caso real (la revision mostro que median la rama
barata): lista de respaldo casi llena, override que alcanza el umbral, veto de
un council de 7 que devuelve el bond, finalize que devuelve el bond, unlock
con la mitad vencida. Pesos regenerados con frame-omni-bencher (Mac; los
canonicos siguen pendientes del Pi 5, L-6). veto_proposal estaba
subdeclarado ~3x: 36M ps 10r/7w -> 112M 21r/10w, proof 6132 -> 16416.
regen-weights.sh: el blob de bench (runtime-benchmarks) se construye en
target-bench/ DENTRO del repo, nunca en target/release/wbuild, que es de donde
sale un set_code. Lo que debe coincidir con lo desplegado es el commit, no el
blob. Dentro del repo porque substrate-wasm-builder busca el Cargo.lock
subiendo desde el target: fuera no lo encuentra y resuelve dependencias
nuevas (medido).
Fuera de RV15, a RV16 (L-11): el override no es un 4/5 real (el bond que el
veto devuelve y el OGC Aye cuentan en el denominador y en el numerador), el
veto sigue siendo posible tras end_block, y un periodo de voto minimo.
Existian antes de RV15; los demostro la misma revision.
cargo test --workspace: 334 passed, 0 failed, 0 ignored.
cargo test -p origin-chain-governance --features runtime-benchmarks: 79 passed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d37a278ba6
commit
a694cbd9f0
10 files changed
+1097
-106
No files matched your search
@@ -28,3 +28,6 @@ contracts/*/Cargo.lock
|
|||||||
# Local config
|
# Local config
|
||||||
.env
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
|
|
||||||
|
# Blob de benchmarks (runtime-benchmarks): NUNCA se despliega. Ver scripts/bench/regen-weights.sh
|
||||||
|
/target-bench
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use frame_benchmarking::v2::*;
|
use frame_benchmarking::v2::*;
|
||||||
use frame_support::traits::fungible::{Inspect, Mutate};
|
use frame_support::traits::fungible::{Inspect, Mutate};
|
||||||
|
use frame_support::traits::Get;
|
||||||
use frame_system::RawOrigin;
|
use frame_system::RawOrigin;
|
||||||
use origin_chain_types::AccountId;
|
use origin_chain_types::AccountId;
|
||||||
|
|
||||||
@@ -52,6 +53,34 @@ fn seed_council<T: Config>(who: &T::AccountId) {
|
|||||||
CouncilSize::<T>::put(1u32);
|
CouncilSize::<T>::put(1u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// RV15: siembra `n` votos vivos respaldados por `who` (propuestas distintas del
|
||||||
|
/// id de los benchmarks), con `until` dado. Es el peor caso de PoV: la lista de
|
||||||
|
/// respaldo se lee y se reescribe entera.
|
||||||
|
fn seed_backing<T: Config>(who: &T::AccountId, n: u32, until: u64) {
|
||||||
|
for i in 0..n {
|
||||||
|
Pallet::<T>::back_vote_with_funds(
|
||||||
|
who,
|
||||||
|
ProposalId([100u8.wrapping_add(i as u8); 32]),
|
||||||
|
BackingKind::Vote,
|
||||||
|
1_000u128.saturating_add(i as u128),
|
||||||
|
until,
|
||||||
|
)
|
||||||
|
.expect("respaldo sembrado");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bond real de la propuesta `id`, con fondos en la cuenta-bond: la rama cara
|
||||||
|
/// del veto y del finalize es la que lo devuelve.
|
||||||
|
fn seed_bond<T: Config>(id: ProposalId) -> T::AccountId {
|
||||||
|
let proposer: T::AccountId = account("proposer", 0, 0);
|
||||||
|
let _ = T::Currency::mint_into(
|
||||||
|
&Pallet::<T>::proposal_bond_account(),
|
||||||
|
MIN_PROPOSAL_STAKE.saturating_mul(2),
|
||||||
|
);
|
||||||
|
ProposalBond::<T>::insert(id, (proposer.clone(), MIN_PROPOSAL_STAKE));
|
||||||
|
proposer
|
||||||
|
}
|
||||||
|
|
||||||
const EM_TITLE: [u8; 32] = [3u8; 32];
|
const EM_TITLE: [u8; 32] = [3u8; 32];
|
||||||
const EM_BODY: [u8; 32] = [4u8; 32];
|
const EM_BODY: [u8; 32] = [4u8; 32];
|
||||||
|
|
||||||
@@ -73,6 +102,14 @@ mod benchmarks {
|
|||||||
#[benchmark]
|
#[benchmark]
|
||||||
fn cast_vote() {
|
fn cast_vote() {
|
||||||
let caller: T::AccountId = whitelisted_caller();
|
let caller: T::AccountId = whitelisted_caller();
|
||||||
|
// RV15: el peso sale del saldo. Peor caso: la cuenta ya respalda
|
||||||
|
// MaxActiveVotes - 1 votos vivos (lista y freeze que leer y reescribir).
|
||||||
|
fund::<T>(&caller);
|
||||||
|
seed_backing::<T>(
|
||||||
|
&caller,
|
||||||
|
T::MaxActiveVotes::get().saturating_sub(1),
|
||||||
|
1_000_000u64,
|
||||||
|
);
|
||||||
let id = ProposalId([7u8; 32]);
|
let id = ProposalId([7u8; 32]);
|
||||||
seed_proposal::<T>(id, ProposalStatus::Voting, 1_000_000u64);
|
seed_proposal::<T>(id, ProposalStatus::Voting, 1_000_000u64);
|
||||||
|
|
||||||
@@ -87,6 +124,8 @@ mod benchmarks {
|
|||||||
let caller: T::AccountId = whitelisted_caller();
|
let caller: T::AccountId = whitelisted_caller();
|
||||||
let id = ProposalId([7u8; 32]);
|
let id = ProposalId([7u8; 32]);
|
||||||
seed_proposal::<T>(id, ProposalStatus::Voting, 0u64);
|
seed_proposal::<T>(id, ProposalStatus::Voting, 0u64);
|
||||||
|
// Rama cara: devuelve el bond (transfer real desde la cuenta-bond).
|
||||||
|
let proposer = seed_bond::<T>(id);
|
||||||
// current_block debe ser > end_block(0) → avanza a 2.
|
// current_block debe ser > end_block(0) → avanza a 2.
|
||||||
frame_system::Pallet::<T>::set_block_number(2u32.into());
|
frame_system::Pallet::<T>::set_block_number(2u32.into());
|
||||||
|
|
||||||
@@ -97,6 +136,8 @@ mod benchmarks {
|
|||||||
Proposals::<T>::get(id).unwrap().status,
|
Proposals::<T>::get(id).unwrap().status,
|
||||||
ProposalStatus::Voting
|
ProposalStatus::Voting
|
||||||
));
|
));
|
||||||
|
assert!(!ProposalBond::<T>::contains_key(id));
|
||||||
|
assert_eq!(T::Currency::balance(&proposer), MIN_PROPOSAL_STAKE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[benchmark]
|
#[benchmark]
|
||||||
@@ -122,15 +163,43 @@ mod benchmarks {
|
|||||||
|
|
||||||
#[benchmark]
|
#[benchmark]
|
||||||
fn veto_proposal() {
|
fn veto_proposal() {
|
||||||
|
// Rama cara: council LLENO (7), 4 vetos vivos previos, y el del caller es el
|
||||||
|
// 5.º que alcanza el umbral 2/3 → recorre todos los vetos, flipa a Rejected,
|
||||||
|
// abre la ventana de override (RV15) y devuelve el bond.
|
||||||
let caller: T::AccountId = whitelisted_caller();
|
let caller: T::AccountId = whitelisted_caller();
|
||||||
seed_council::<T>(&caller);
|
|
||||||
let id = ProposalId([7u8; 32]);
|
let id = ProposalId([7u8; 32]);
|
||||||
seed_proposal::<T>(id, ProposalStatus::Voting, 1_000_000u64);
|
seed_proposal::<T>(id, ProposalStatus::Voting, 1_000_000u64);
|
||||||
|
let proposer = seed_bond::<T>(id);
|
||||||
|
let mut miembros: alloc::vec::Vec<T::AccountId> = (0..MAX_COUNCIL_SIZE - 1)
|
||||||
|
.map(|i| account("council", i, 0))
|
||||||
|
.collect();
|
||||||
|
miembros.push(caller.clone());
|
||||||
|
for m in &miembros {
|
||||||
|
Council::<T>::insert(
|
||||||
|
m,
|
||||||
|
CouncilMember {
|
||||||
|
account: AccountId::new([0u8; 32]),
|
||||||
|
joined_at_block: 0,
|
||||||
|
role: CouncilRole::Member,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
CouncilSize::<T>::put(MAX_COUNCIL_SIZE);
|
||||||
|
let previos = council_veto_threshold(MAX_COUNCIL_SIZE) - 1;
|
||||||
|
for m in miembros.iter().take(previos as usize) {
|
||||||
|
VetoVotes::<T>::insert(id, m, ());
|
||||||
|
}
|
||||||
|
|
||||||
#[extrinsic_call]
|
#[extrinsic_call]
|
||||||
veto_proposal(RawOrigin::Signed(caller.clone()), id);
|
veto_proposal(RawOrigin::Signed(caller.clone()), id);
|
||||||
|
|
||||||
assert!(VetoVotes::<T>::contains_key(id, &caller));
|
assert!(VetoVotes::<T>::contains_key(id, &caller));
|
||||||
|
assert!(matches!(
|
||||||
|
Proposals::<T>::get(id).unwrap().status,
|
||||||
|
ProposalStatus::Rejected
|
||||||
|
));
|
||||||
|
assert!(OverrideDeadline::<T>::contains_key(id));
|
||||||
|
assert_eq!(T::Currency::balance(&proposer), MIN_PROPOSAL_STAKE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[benchmark]
|
#[benchmark]
|
||||||
@@ -160,11 +229,24 @@ mod benchmarks {
|
|||||||
let id = ProposalId([7u8; 32]);
|
let id = ProposalId([7u8; 32]);
|
||||||
seed_proposal::<T>(id, ProposalStatus::Rejected, 0u64);
|
seed_proposal::<T>(id, ProposalStatus::Rejected, 0u64);
|
||||||
VetoRejected::<T>::insert(id, ());
|
VetoRejected::<T>::insert(id, ());
|
||||||
|
// RV15: ventana abierta, peso respaldado por saldo y la lista de respaldo casi
|
||||||
|
// llena (peor caso). Y rama cara: el override ALCANZA el umbral y aprueba.
|
||||||
|
OverrideDeadline::<T>::insert(id, 1_000_000u64);
|
||||||
|
fund::<T>(&caller);
|
||||||
|
seed_backing::<T>(
|
||||||
|
&caller,
|
||||||
|
T::MaxActiveVotes::get().saturating_sub(1),
|
||||||
|
1_000_000u64,
|
||||||
|
);
|
||||||
|
|
||||||
#[extrinsic_call]
|
#[extrinsic_call]
|
||||||
override_council_veto(RawOrigin::Signed(caller.clone()), id, 100u128);
|
override_council_veto(RawOrigin::Signed(caller.clone()), id, MIN_PROPOSAL_STAKE);
|
||||||
|
|
||||||
assert!(OverrideVotes::<T>::contains_key(id, &caller));
|
assert!(OverrideVotes::<T>::contains_key(id, &caller));
|
||||||
|
assert!(matches!(
|
||||||
|
Proposals::<T>::get(id).unwrap().status,
|
||||||
|
ProposalStatus::Approved
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[benchmark]
|
#[benchmark]
|
||||||
@@ -222,5 +304,33 @@ mod benchmarks {
|
|||||||
assert!(EmergencyEndorsements::<T>::contains_key(content_id, &caller));
|
assert!(EmergencyEndorsements::<T>::contains_key(content_id, &caller));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[benchmark]
|
||||||
|
fn unlock_vote_funds() {
|
||||||
|
// Peor caso: lista de respaldo LLENA, la mitad vencida (until = 1) y la otra
|
||||||
|
// mitad viva → se poda, se recalcula el máximo y se reescribe la lista.
|
||||||
|
let caller: T::AccountId = whitelisted_caller();
|
||||||
|
let votante: T::AccountId = account("votante", 0, 0);
|
||||||
|
fund::<T>(&votante);
|
||||||
|
let max = T::MaxActiveVotes::get();
|
||||||
|
let vencidos = max / 2;
|
||||||
|
seed_backing::<T>(&votante, vencidos, 1u64);
|
||||||
|
for i in vencidos..max {
|
||||||
|
Pallet::<T>::back_vote_with_funds(
|
||||||
|
&votante,
|
||||||
|
ProposalId([100u8.wrapping_add(i as u8); 32]),
|
||||||
|
BackingKind::Vote,
|
||||||
|
500u128,
|
||||||
|
1_000_000u64,
|
||||||
|
)
|
||||||
|
.expect("respaldo vivo");
|
||||||
|
}
|
||||||
|
frame_system::Pallet::<T>::set_block_number(2u32.into());
|
||||||
|
|
||||||
|
#[extrinsic_call]
|
||||||
|
unlock_vote_funds(RawOrigin::Signed(caller), votante.clone());
|
||||||
|
|
||||||
|
assert_eq!(VoteLocks::<T>::get(&votante).len() as u32, max - vencidos);
|
||||||
|
}
|
||||||
|
|
||||||
impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
|
impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
|
||||||
}
|
}
|
||||||
@@ -124,7 +124,7 @@ sp_api::decl_runtime_apis! {
|
|||||||
#[frame_support::pallet]
|
#[frame_support::pallet]
|
||||||
pub mod pallet {
|
pub mod pallet {
|
||||||
use frame_support::pallet_prelude::*;
|
use frame_support::pallet_prelude::*;
|
||||||
use frame_support::traits::fungible::{Inspect, Mutate};
|
use frame_support::traits::fungible::{freeze, Inspect, Mutate};
|
||||||
use frame_support::traits::tokens::Preservation;
|
use frame_support::traits::tokens::Preservation;
|
||||||
use frame_support::PalletId;
|
use frame_support::PalletId;
|
||||||
use frame_system::pallet_prelude::*;
|
use frame_system::pallet_prelude::*;
|
||||||
@@ -192,6 +192,22 @@ pub mod pallet {
|
|||||||
/// 14 days × 24 hours × 600 blocks/hour (@ 6s slot Aura) = 201,600 blocks.
|
/// 14 days × 24 hours × 600 blocks/hour (@ 6s slot Aura) = 201,600 blocks.
|
||||||
pub const DEFAULT_VOTING_PERIOD_BLOCKS: u64 = 14 * 24 * 600;
|
pub const DEFAULT_VOTING_PERIOD_BLOCKS: u64 = 14 * 24 * 600;
|
||||||
|
|
||||||
|
/// RV15: ventana para revertir un veto del council, contada desde el bloque en
|
||||||
|
/// que el veto alcanza su umbral. Mide lo mismo que un voto normal (14 días).
|
||||||
|
///
|
||||||
|
/// Antes no había ventana: una propuesta vetada aceptaba votos de override para
|
||||||
|
/// siempre, así que podía resucitarse años después. Y con peso real (RV15) el
|
||||||
|
/// OGC que respalda un override tiene que liberarse ALGÚN día: sin ventana, o se
|
||||||
|
/// congelaba para siempre o el voto dejaba de estar respaldado.
|
||||||
|
pub const OVERRIDE_WINDOW_BLOCKS: u64 = DEFAULT_VOTING_PERIOD_BLOCKS;
|
||||||
|
|
||||||
|
/// RV15: periodo de voto máximo que puede pedir un proponente (28 días).
|
||||||
|
///
|
||||||
|
/// Antes era libre hasta `u64::MAX`. Con el voto respaldado por OGC eso era un
|
||||||
|
/// arma: una propuesta de periodo casi eterno congelaba casi para siempre el OGC
|
||||||
|
/// de quien votara en ella (demostrado por la revisión adversaria de RV15).
|
||||||
|
pub const MAX_VOTING_PERIOD_BLOCKS: u64 = 2 * DEFAULT_VOTING_PERIOD_BLOCKS;
|
||||||
|
|
||||||
/// Emergency voting period canonical canonical 48 hours per CHN-4 5.7.
|
/// Emergency voting period canonical canonical 48 hours per CHN-4 5.7.
|
||||||
/// 48 hours × 600 blocks/hour (@ 6s slot Aura) = 28,800 blocks.
|
/// 48 hours × 600 blocks/hour (@ 6s slot Aura) = 28,800 blocks.
|
||||||
pub const EMERGENCY_VOTING_PERIOD_BLOCKS: u64 = 48 * 600;
|
pub const EMERGENCY_VOTING_PERIOD_BLOCKS: u64 = 48 * 600;
|
||||||
@@ -208,6 +224,35 @@ pub mod pallet {
|
|||||||
(total_stake.saturating_mul(4).saturating_add(4)) / 5
|
(total_stake.saturating_mul(4).saturating_add(4)) / 5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// RV15: qué respalda un tramo de OGC congelado.
|
||||||
|
#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, Copy, PartialEq, Eq, RuntimeDebug)]
|
||||||
|
pub enum BackingKind {
|
||||||
|
/// Un voto del periodo normal (`cast_vote`).
|
||||||
|
Vote,
|
||||||
|
/// Un voto para revertir un veto (`override_council_veto`).
|
||||||
|
Override,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// RV15: el OGC que respalda UN voto vivo.
|
||||||
|
///
|
||||||
|
/// Un registro por voto, no uno por cuenta. La primera versión fusionaba todo
|
||||||
|
/// en un único lock (máximo importe hasta el bloque más tardío) y la revisión
|
||||||
|
/// adversaria demostró por qué no sirve: un voto mínimo en una propuesta de
|
||||||
|
/// periodo enorme arrastraba el voto MAYOR de la cuenta hasta ese bloque, para
|
||||||
|
/// siempre, y un lock vencido revivía con el siguiente voto. Con un registro por
|
||||||
|
/// voto, cada tramo vence solo y el freeze es siempre el MÁXIMO DE LOS VIVOS.
|
||||||
|
#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, Copy, PartialEq, Eq, RuntimeDebug)]
|
||||||
|
pub struct VoteBacking {
|
||||||
|
/// Propuesta a la que respalda.
|
||||||
|
pub proposal: ProposalId,
|
||||||
|
/// Voto normal u override.
|
||||||
|
pub kind: BackingKind,
|
||||||
|
/// OGC que respalda este voto.
|
||||||
|
pub amount: u128,
|
||||||
|
/// Último bloque (inclusive) en que este voto aún puede cambiar el resultado.
|
||||||
|
pub until: u64,
|
||||||
|
}
|
||||||
|
|
||||||
/// Proposal canonical struct stored on-chain per pallet (Foundation OIP).
|
/// Proposal canonical struct stored on-chain per pallet (Foundation OIP).
|
||||||
#[derive(
|
#[derive(
|
||||||
Encode, Decode, DecodeWithMemTracking, MaxEncodedLen, TypeInfo, Clone, PartialEq, Eq,
|
Encode, Decode, DecodeWithMemTracking, MaxEncodedLen, TypeInfo, Clone, PartialEq, Eq,
|
||||||
@@ -248,7 +293,21 @@ pub mod pallet {
|
|||||||
/// FIX-6 (V2-CA2/V3-C3): Currency real (fungible) para mover OGC de la
|
/// FIX-6 (V2-CA2/V3-C3): Currency real (fungible) para mover OGC de la
|
||||||
/// tesorería. La tesorería deja de ser un contador u128 y pasa a ser una
|
/// tesorería. La tesorería deja de ser un contador u128 y pasa a ser una
|
||||||
/// cuenta real respaldada por pallet_balances.
|
/// cuenta real respaldada por pallet_balances.
|
||||||
type Currency: Inspect<Self::AccountId, Balance = u128> + Mutate<Self::AccountId>;
|
///
|
||||||
|
/// RV15: además congela (`freeze`) el OGC que respalda un voto, para que el
|
||||||
|
/// mismo OGC no pueda votar dos veces pasando por una transferencia.
|
||||||
|
type Currency: Inspect<Self::AccountId, Balance = u128>
|
||||||
|
+ Mutate<Self::AccountId>
|
||||||
|
+ freeze::Mutate<Self::AccountId, Id = Self::RuntimeFreezeReason>;
|
||||||
|
|
||||||
|
/// RV15: el enum agregado de razones de congelación del runtime.
|
||||||
|
type RuntimeFreezeReason: From<FreezeReason>;
|
||||||
|
|
||||||
|
/// RV15: cuántos votos VIVOS puede respaldar una cuenta a la vez. Los
|
||||||
|
/// vencidos se descartan solos al votar o desbloquear, así que el límite es
|
||||||
|
/// de votos simultáneos, no históricos.
|
||||||
|
#[pallet::constant]
|
||||||
|
type MaxActiveVotes: Get<u32>;
|
||||||
|
|
||||||
/// FIX-6: PalletId del que se deriva la cuenta-tesorería (vault). Cuenta
|
/// FIX-6: PalletId del que se deriva la cuenta-tesorería (vault). Cuenta
|
||||||
/// determinística sin private key — nadie la controla por wallet, solo la
|
/// determinística sin private key — nadie la controla por wallet, solo la
|
||||||
@@ -271,6 +330,33 @@ pub mod pallet {
|
|||||||
#[pallet::storage_version(STORAGE_VERSION)]
|
#[pallet::storage_version(STORAGE_VERSION)]
|
||||||
pub struct Pallet<T>(_);
|
pub struct Pallet<T>(_);
|
||||||
|
|
||||||
|
/// RV15: por qué este pallet congela OGC.
|
||||||
|
#[pallet::composite_enum]
|
||||||
|
pub enum FreezeReason {
|
||||||
|
/// OGC que respalda un voto (o un override) que todavía puede cambiar un
|
||||||
|
/// resultado.
|
||||||
|
#[codec(index = 0)]
|
||||||
|
GovernanceVote,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// RV15: los votos vivos que respalda cada cuenta (ver [`VoteBacking`]). El
|
||||||
|
/// freeze `GovernanceVote` de la cuenta es el máximo de sus `amount`.
|
||||||
|
#[pallet::storage]
|
||||||
|
pub type VoteLocks<T: Config> = StorageMap<
|
||||||
|
_,
|
||||||
|
Blake2_128Concat,
|
||||||
|
T::AccountId,
|
||||||
|
BoundedVec<VoteBacking, T::MaxActiveVotes>,
|
||||||
|
ValueQuery,
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// RV15: último bloque (inclusive) en que se acepta un override sobre una
|
||||||
|
/// propuesta vetada. Se escribe cuando el veto alcanza su umbral. Sin entrada,
|
||||||
|
/// no hay override posible: falla cerrado.
|
||||||
|
#[pallet::storage]
|
||||||
|
pub type OverrideDeadline<T: Config> =
|
||||||
|
StorageMap<_, Blake2_128Concat, ProposalId, u64, OptionQuery>;
|
||||||
|
|
||||||
/// CHN-4 canonical: `Proposals<StorageMap<ProposalId, Proposal>>` canonical.
|
/// CHN-4 canonical: `Proposals<StorageMap<ProposalId, Proposal>>` canonical.
|
||||||
#[pallet::storage]
|
#[pallet::storage]
|
||||||
#[pallet::getter(fn proposal_of)]
|
#[pallet::getter(fn proposal_of)]
|
||||||
@@ -557,6 +643,17 @@ pub mod pallet {
|
|||||||
/// Treasury balance canonical post-disbursement.
|
/// Treasury balance canonical post-disbursement.
|
||||||
remaining_balance: u128,
|
remaining_balance: u128,
|
||||||
},
|
},
|
||||||
|
/// RV15: se liberó OGC que respaldaba votos que ya no pueden cambiar un
|
||||||
|
/// resultado. Va AL FINAL del enum a propósito: insertarlo en medio desplazaba
|
||||||
|
/// el índice SCALE de tres eventos existentes (revisión adversaria de RV15).
|
||||||
|
VoteFundsUnlocked {
|
||||||
|
/// Cuenta cuyo OGC se libera.
|
||||||
|
who: T::AccountId,
|
||||||
|
/// OGC que deja de estar congelado.
|
||||||
|
released: u128,
|
||||||
|
/// OGC que sigue congelado por votos todavía vivos.
|
||||||
|
still_frozen: u128,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pallet errors canonical.
|
/// Pallet errors canonical.
|
||||||
@@ -616,6 +713,22 @@ pub mod pallet {
|
|||||||
/// Audit 2026-07-04 (B): el council member ya endosó esta propuesta de
|
/// Audit 2026-07-04 (B): el council member ya endosó esta propuesta de
|
||||||
/// emergencia (anti doble-endoso).
|
/// emergencia (anti doble-endoso).
|
||||||
AlreadyEndorsed,
|
AlreadyEndorsed,
|
||||||
|
/// RV15: el peso del voto supera el OGC de la cuenta. El peso sale del
|
||||||
|
/// saldo, no de lo que declara el votante (hueco medido por Palace el
|
||||||
|
/// 2026-09-06).
|
||||||
|
VoteWeightExceedsBalance,
|
||||||
|
/// RV15: la ventana para revertir este veto ya cerró (o la propuesta no
|
||||||
|
/// tiene ventana registrada).
|
||||||
|
OverrideWindowClosed,
|
||||||
|
/// RV15: la cuenta no tiene OGC congelado por votos.
|
||||||
|
NoVoteLock,
|
||||||
|
/// RV15: ninguno de los votos de la cuenta ha vencido todavía; su OGC sigue
|
||||||
|
/// congelado.
|
||||||
|
VoteFundsStillLocked,
|
||||||
|
/// RV15: el periodo de voto pedido supera `MAX_VOTING_PERIOD_BLOCKS`.
|
||||||
|
VotingPeriodTooLong,
|
||||||
|
/// RV15: la cuenta ya respalda `MaxActiveVotes` votos vivos.
|
||||||
|
TooManyActiveVotes,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Minimum stake canonical proposal submission per CHN-4 5.3.
|
/// Minimum stake canonical proposal submission per CHN-4 5.3.
|
||||||
@@ -646,6 +759,10 @@ pub mod pallet {
|
|||||||
) -> DispatchResult {
|
) -> DispatchResult {
|
||||||
let who = ensure_signed(origin)?;
|
let who = ensure_signed(origin)?;
|
||||||
ensure!(stake >= MIN_PROPOSAL_STAKE, Error::<T>::StakeInsufficient);
|
ensure!(stake >= MIN_PROPOSAL_STAKE, Error::<T>::StakeInsufficient);
|
||||||
|
ensure!(
|
||||||
|
voting_period_blocks <= MAX_VOTING_PERIOD_BLOCKS,
|
||||||
|
Error::<T>::VotingPeriodTooLong
|
||||||
|
);
|
||||||
|
|
||||||
let proposer_acct = AccountId::new(account_bytes::<T>(&who));
|
let proposer_acct = AccountId::new(account_bytes::<T>(&who));
|
||||||
let id = crate::derive_proposal_id(&proposer_acct, &title_hash, &body_hash);
|
let id = crate::derive_proposal_id(&proposer_acct, &title_hash, &body_hash);
|
||||||
@@ -731,6 +848,17 @@ pub mod pallet {
|
|||||||
Error::<T>::AlreadyVoted
|
Error::<T>::AlreadyVoted
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// RV15: el peso sale del saldo y queda congelado hasta que el voto ya no
|
||||||
|
// pueda cambiar el resultado (fin del periodo de voto). Sin el freeze,
|
||||||
|
// el mismo OGC votaría otra vez desde otra cuenta tras una transferencia.
|
||||||
|
Self::back_vote_with_funds(
|
||||||
|
&who,
|
||||||
|
proposal_id,
|
||||||
|
BackingKind::Vote,
|
||||||
|
stake_weight,
|
||||||
|
proposal.end_block,
|
||||||
|
)?;
|
||||||
|
|
||||||
match stance {
|
match stance {
|
||||||
VoteStance::Aye => {
|
VoteStance::Aye => {
|
||||||
proposal.yes_weight = proposal.yes_weight.saturating_add(stake_weight)
|
proposal.yes_weight = proposal.yes_weight.saturating_add(stake_weight)
|
||||||
@@ -948,6 +1076,11 @@ pub mod pallet {
|
|||||||
// Marca: rechazado por VETO del council (no por voto popular) →
|
// Marca: rechazado por VETO del council (no por voto popular) →
|
||||||
// única vía elegible para override_council_veto.
|
// única vía elegible para override_council_veto.
|
||||||
VetoRejected::<T>::insert(proposal_id, ());
|
VetoRejected::<T>::insert(proposal_id, ());
|
||||||
|
// RV15: el override tiene ventana, contada desde este bloque.
|
||||||
|
OverrideDeadline::<T>::insert(
|
||||||
|
proposal_id,
|
||||||
|
current_block_u64::<T>().saturating_add(OVERRIDE_WINDOW_BLOCKS),
|
||||||
|
);
|
||||||
// Audit 2026-07-04: la propuesta salió de Voting (vetada) → devuelve
|
// Audit 2026-07-04: la propuesta salió de Voting (vetada) → devuelve
|
||||||
// el bond al proponente (si no, el stake de una propuesta vetada
|
// el bond al proponente (si no, el stake de una propuesta vetada
|
||||||
// quedaría atrapado para siempre — no hay withdraw dispatchable).
|
// quedaría atrapado para siempre — no hay withdraw dispatchable).
|
||||||
@@ -1060,6 +1193,22 @@ pub mod pallet {
|
|||||||
Error::<T>::AlreadyOverrideVoted
|
Error::<T>::AlreadyOverrideVoted
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// RV15: el override tiene ventana, y su peso sale del saldo y queda
|
||||||
|
// congelado hasta que la ventana cierre.
|
||||||
|
let deadline =
|
||||||
|
OverrideDeadline::<T>::get(proposal_id).ok_or(Error::<T>::OverrideWindowClosed)?;
|
||||||
|
ensure!(
|
||||||
|
current_block_u64::<T>() <= deadline,
|
||||||
|
Error::<T>::OverrideWindowClosed
|
||||||
|
);
|
||||||
|
Self::back_vote_with_funds(
|
||||||
|
&who,
|
||||||
|
proposal_id,
|
||||||
|
BackingKind::Override,
|
||||||
|
stake_weight,
|
||||||
|
deadline,
|
||||||
|
)?;
|
||||||
|
|
||||||
OverrideVotes::<T>::insert(proposal_id, &who, stake_weight);
|
OverrideVotes::<T>::insert(proposal_id, &who, stake_weight);
|
||||||
let new_total = OverrideStakeTotal::<T>::get(proposal_id)
|
let new_total = OverrideStakeTotal::<T>::get(proposal_id)
|
||||||
.saturating_add(stake_weight);
|
.saturating_add(stake_weight);
|
||||||
@@ -1296,6 +1445,111 @@ pub mod pallet {
|
|||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// RV15: libera el OGC que respaldaba votos de `who` que ya no pueden cambiar
|
||||||
|
/// un resultado (pasó su `until`). Lo que respalda votos todavía vivos sigue
|
||||||
|
/// congelado.
|
||||||
|
///
|
||||||
|
/// Lo puede llamar CUALQUIERA, como `unlock` de `pallet-conviction-voting`: la
|
||||||
|
/// condición es objetiva, y quien votó con todo su saldo no puede pagar la
|
||||||
|
/// comisión de su propio desbloqueo (revisión adversaria de RV15).
|
||||||
|
#[pallet::call_index(13)]
|
||||||
|
#[pallet::weight(T::WeightInfo::unlock_vote_funds())]
|
||||||
|
pub fn unlock_vote_funds(origin: OriginFor<T>, who: T::AccountId) -> DispatchResult {
|
||||||
|
ensure_signed(origin)?;
|
||||||
|
let mut backing = VoteLocks::<T>::get(&who);
|
||||||
|
ensure!(!backing.is_empty(), Error::<T>::NoVoteLock);
|
||||||
|
let before = max_backing(&backing);
|
||||||
|
let now = current_block_u64::<T>();
|
||||||
|
let n = backing.len();
|
||||||
|
backing.retain(|b| b.until >= now);
|
||||||
|
ensure!(backing.len() < n, Error::<T>::VoteFundsStillLocked);
|
||||||
|
let after = max_backing(&backing);
|
||||||
|
Self::apply_vote_freeze(&who, backing, after)?;
|
||||||
|
Self::deposit_event(Event::VoteFundsUnlocked {
|
||||||
|
who,
|
||||||
|
released: before.saturating_sub(after),
|
||||||
|
still_frozen: after,
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// El mayor OGC respaldado por una lista de votos (0 si está vacía).
|
||||||
|
fn max_backing(backing: &[VoteBacking]) -> u128 {
|
||||||
|
backing.iter().map(|b| b.amount).max().unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bloque actual como `u64` (el tipo de `end_block` y de las ventanas).
|
||||||
|
fn current_block_u64<T: Config>() -> u64 {
|
||||||
|
<frame_system::Pallet<T>>::block_number().saturated_into::<u64>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// RV15 — el OGC que respalda un voto.
|
||||||
|
impl<T: Config> Pallet<T> {
|
||||||
|
/// Exige que `weight` no supere el OGC LIBRE de `who` y lo deja congelado
|
||||||
|
/// mientras este voto pueda cambiar un resultado (hasta `until`).
|
||||||
|
///
|
||||||
|
/// Antes descarta los respaldos ya vencidos de la cuenta, así que un voto
|
||||||
|
/// muerto nunca vuelve a congelarse. El freeze resultante es el MÁXIMO de los
|
||||||
|
/// votos vivos: el mismo OGC puede respaldar votos en propuestas distintas
|
||||||
|
/// (se solapan, como en Polkadot), pero no puede salir de la cuenta mientras
|
||||||
|
/// un voto que respalda siga vivo. Eso cierra votar, transferir y votar otra
|
||||||
|
/// vez desde otra cuenta.
|
||||||
|
///
|
||||||
|
/// Un peso 0 no congela nada ni toca el respaldo que ya hubiera.
|
||||||
|
///
|
||||||
|
/// Límite conocido: el freeze de `pallet-balances` se cumple sobre libre +
|
||||||
|
/// retenido. Si la cuenta tiene OGC en hold (staking), lo retenido puede
|
||||||
|
/// sostener el freeze mientras lo libre sale: en la práctica el OGC en hold
|
||||||
|
/// termina respaldando el voto, que es la semántica de Polkadot. No infla el
|
||||||
|
/// total: ninguna cuenta respalda más de lo que posee.
|
||||||
|
pub(crate) fn back_vote_with_funds(
|
||||||
|
who: &T::AccountId,
|
||||||
|
proposal: ProposalId,
|
||||||
|
kind: BackingKind,
|
||||||
|
weight: u128,
|
||||||
|
until: u64,
|
||||||
|
) -> DispatchResult {
|
||||||
|
ensure!(
|
||||||
|
weight <= T::Currency::balance(who),
|
||||||
|
Error::<T>::VoteWeightExceedsBalance
|
||||||
|
);
|
||||||
|
if weight == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let now = current_block_u64::<T>();
|
||||||
|
let mut backing = VoteLocks::<T>::get(who);
|
||||||
|
backing.retain(|b| b.until >= now);
|
||||||
|
backing
|
||||||
|
.try_push(VoteBacking {
|
||||||
|
proposal,
|
||||||
|
kind,
|
||||||
|
amount: weight,
|
||||||
|
until,
|
||||||
|
})
|
||||||
|
.map_err(|_| Error::<T>::TooManyActiveVotes)?;
|
||||||
|
let frozen = max_backing(&backing);
|
||||||
|
Self::apply_vote_freeze(who, backing, frozen)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deja el freeze `GovernanceVote` de `who` en `frozen` y guarda su respaldo;
|
||||||
|
/// sin votos vivos, descongela y borra el registro.
|
||||||
|
fn apply_vote_freeze(
|
||||||
|
who: &T::AccountId,
|
||||||
|
backing: BoundedVec<VoteBacking, T::MaxActiveVotes>,
|
||||||
|
frozen: u128,
|
||||||
|
) -> DispatchResult {
|
||||||
|
let reason = FreezeReason::GovernanceVote.into();
|
||||||
|
if backing.is_empty() {
|
||||||
|
<T::Currency as freeze::Mutate<T::AccountId>>::thaw(&reason, who)?;
|
||||||
|
VoteLocks::<T>::remove(who);
|
||||||
|
} else {
|
||||||
|
<T::Currency as freeze::Mutate<T::AccountId>>::set_freeze(&reason, who, frozen)?;
|
||||||
|
VoteLocks::<T>::insert(who, backing);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FIX-6 — helpers de la tesorería real (cuenta respaldada por pallet_balances).
|
/// FIX-6 — helpers de la tesorería real (cuenta respaldada por pallet_balances).
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ impl frame_system::Config for Test {
|
|||||||
impl pallet_balances::Config for Test {
|
impl pallet_balances::Config for Test {
|
||||||
type AccountStore = System;
|
type AccountStore = System;
|
||||||
type Balance = u128;
|
type Balance = u128;
|
||||||
|
// RV15: governance congela el OGC que respalda un voto.
|
||||||
|
type FreezeIdentifier = RuntimeFreezeReason;
|
||||||
|
type MaxFreezes = frame_support::traits::VariantCountOf<RuntimeFreezeReason>;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame_support::parameter_types! {
|
frame_support::parameter_types! {
|
||||||
@@ -42,6 +45,9 @@ frame_support::parameter_types! {
|
|||||||
impl origin_chain_governance::Config for Test {
|
impl origin_chain_governance::Config for Test {
|
||||||
type RuntimeEvent = RuntimeEvent;
|
type RuntimeEvent = RuntimeEvent;
|
||||||
type Currency = Balances;
|
type Currency = Balances;
|
||||||
|
type RuntimeFreezeReason = RuntimeFreezeReason;
|
||||||
|
// Bajo a propósito: el límite de votos vivos tiene que poder probarse.
|
||||||
|
type MaxActiveVotes = frame_support::traits::ConstU32<4>;
|
||||||
type TreasuryPalletId = TestTreasuryPalletId;
|
type TreasuryPalletId = TestTreasuryPalletId;
|
||||||
type WeightInfo = ();
|
type WeightInfo = ();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
|
|
||||||
use crate::mock::{
|
use crate::mock::{
|
||||||
alice_account, alice_origin, bob_account, bob_origin, charlie_account, charlie_origin,
|
alice_account, alice_origin, bob_account, bob_origin, charlie_account, charlie_origin,
|
||||||
new_test_ext, run_to_block, Balances, Governance, RuntimeEvent, System, Test, INITIAL_BALANCE,
|
new_test_ext, run_to_block, Balances, Governance, RuntimeEvent, RuntimeFreezeReason,
|
||||||
|
RuntimeOrigin, System, Test, INITIAL_BALANCE,
|
||||||
};
|
};
|
||||||
use crate::pallet::{Proposal, ProposalStatus, MIN_PROPOSAL_STAKE};
|
use crate::pallet::{Proposal, ProposalStatus, MIN_PROPOSAL_STAKE};
|
||||||
use crate::{derive_proposal_id, Error, Event, Proposals, Votes};
|
use crate::{derive_proposal_id, Error, Event, Proposals, Votes};
|
||||||
@@ -1145,19 +1146,12 @@ fn scenario_10_lifecycle_walkthrough_canonical() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// HUECO ABIERTO — medido por Palace el 2026-09-06, confirmado por Charon el
|
/// CERRADO en RV15. Hueco medido por Palace el 2026-09-06 y confirmado por Charon el
|
||||||
/// 2026-09-23 sobre `63918f3`. `cast_vote` (y `override_council_veto`) suman el
|
/// 2026-09-23 sobre `63918f3`: `cast_vote` (y `override_council_veto`) sumaban el
|
||||||
/// `stake_weight` que DECLARA el votante sin contrastarlo con nada: el diseño dice
|
/// `stake_weight` que DECLARA el votante sin contrastarlo con nada. Este test estuvo
|
||||||
/// «1 OGC = 1 voto» (doc de `lib.rs:403`) y el código es un contador que suma lo que
|
/// publicado en rojo (`d37a278`, con `#[ignore]`) antes de la cura; quitar el
|
||||||
/// le digan. Hoy no drena la tesorería porque `treasury_disbursement` exige además
|
/// `ignore` era el criterio de cierre.
|
||||||
/// `ensure_root`, pero cualquiera aprueba o bloquea una propuesta con `u128::MAX`,
|
|
||||||
/// y el día que se retire el sudo (L-7) y la gobernanza ejecute (L-8) sí la drena.
|
|
||||||
///
|
|
||||||
/// El `ignore` NO lo esconde: `cargo test -- --ignored` lo enseña en rojo, y
|
|
||||||
/// QUITARLO es el criterio de cierre de RV15 (peso derivado del saldo + un freeze
|
|
||||||
/// para que el mismo OGC no vote dos veces pasando por una transferencia).
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "RV15: cast_vote acepta el peso que declara el votante (hueco medido 2026-09-06)"]
|
|
||||||
fn un_voto_no_puede_pesar_mas_que_el_saldo_del_votante() {
|
fn un_voto_no_puede_pesar_mas_que_el_saldo_del_votante() {
|
||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
let id = submit_default(alice_origin());
|
let id = submit_default(alice_origin());
|
||||||
@@ -1184,3 +1178,471 @@ fn un_voto_no_puede_pesar_mas_que_el_saldo_del_votante() {
|
|||||||
assert_eq!(p.yes_weight, saldo, "un voto legítimo no contó entero");
|
assert_eq!(p.yes_weight, saldo, "un voto legítimo no contó entero");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════
|
||||||
|
// RV15 — el peso de un voto sale del saldo y ese OGC queda congelado mientras
|
||||||
|
// el voto pueda cambiar un resultado. Cada test lleva su control positivo, y
|
||||||
|
// cada uno mata al menos una mutación que la revisión adversaria de RV15 vio
|
||||||
|
// sobrevivir a la primera versión de esta suite.
|
||||||
|
// ═══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
/// OGC congelado HOY por votos de gobernanza (lo que mide `pallet-balances`, no
|
||||||
|
/// el registro del pallet: la revisión mostró que mirar solo el registro deja
|
||||||
|
/// vivo un freeze equivocado).
|
||||||
|
fn congelado_por_votos(who: &sp_runtime::AccountId32) -> u128 {
|
||||||
|
use frame_support::traits::fungible::InspectFreeze;
|
||||||
|
let razon: RuntimeFreezeReason = crate::FreezeReason::GovernanceVote.into();
|
||||||
|
Balances::balance_frozen(&razon, who)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Otra propuesta de Alice, con su propio periodo.
|
||||||
|
fn propuesta_con_periodo(semilla: u8, periodo: u64) -> ProposalId {
|
||||||
|
let (t, b) = ([semilla; 32], [semilla.wrapping_add(100); 32]);
|
||||||
|
assert_ok!(Governance::submit_proposal(
|
||||||
|
alice_origin(),
|
||||||
|
t,
|
||||||
|
b,
|
||||||
|
periodo,
|
||||||
|
MIN_PROPOSAL_STAKE,
|
||||||
|
));
|
||||||
|
derive_proposal_id(&AccountId::new(alice_account_bytes()), &t, &b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fin_de(id: ProposalId) -> u64 {
|
||||||
|
Proposals::<Test>::get(id).expect("propuesta").end_block
|
||||||
|
}
|
||||||
|
|
||||||
|
/// El mismo OGC no puede votar dos veces pasando por una transferencia: el que
|
||||||
|
/// respalda un voto vivo no sale de la cuenta.
|
||||||
|
#[test]
|
||||||
|
fn el_ogc_que_respalda_un_voto_no_sale_de_la_cuenta_mientras_el_voto_vive() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let id = submit_default(alice_origin());
|
||||||
|
let saldo = Balances::free_balance(bob_account());
|
||||||
|
let peso = saldo / 2;
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
id,
|
||||||
|
VoteStance::Aye,
|
||||||
|
peso
|
||||||
|
));
|
||||||
|
assert_eq!(congelado_por_votos(&bob_account()), peso);
|
||||||
|
|
||||||
|
let r = Balances::transfer_allow_death(bob_origin(), charlie_account(), saldo - peso + 1);
|
||||||
|
assert!(
|
||||||
|
r.is_err(),
|
||||||
|
"salió de la cuenta OGC congelado por un voto vivo"
|
||||||
|
);
|
||||||
|
assert_eq!(Balances::free_balance(bob_account()), saldo);
|
||||||
|
|
||||||
|
// Control positivo: lo que NO respalda el voto se mueve libre.
|
||||||
|
assert_ok!(Balances::transfer_allow_death(
|
||||||
|
bob_origin(),
|
||||||
|
charlie_account(),
|
||||||
|
saldo - peso
|
||||||
|
));
|
||||||
|
assert_eq!(Balances::free_balance(bob_account()), peso);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Con varios votos vivos, el freeze REAL es el mayor, no el último. Primero la
|
||||||
|
/// propuesta larga con más peso, luego la corta con menos: congelar el peso del
|
||||||
|
/// voto actual dejaría 300 y liberaría 200 que respaldan un voto vivo.
|
||||||
|
#[test]
|
||||||
|
fn el_freeze_real_es_el_mayor_de_los_votos_vivos_no_el_ultimo() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let corta = submit_default(alice_origin());
|
||||||
|
let larga = propuesta_con_periodo(11, 3 * VOTING_PERIOD);
|
||||||
|
let saldo = Balances::free_balance(bob_account());
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
larga,
|
||||||
|
VoteStance::Nay,
|
||||||
|
500
|
||||||
|
));
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
corta,
|
||||||
|
VoteStance::Aye,
|
||||||
|
300
|
||||||
|
));
|
||||||
|
assert_eq!(congelado_por_votos(&bob_account()), 500);
|
||||||
|
|
||||||
|
// El ataque con dinero real: sacar los 200 que respaldan el voto largo.
|
||||||
|
assert!(
|
||||||
|
Balances::transfer_allow_death(bob_origin(), charlie_account(), saldo - 300).is_err()
|
||||||
|
);
|
||||||
|
// Control positivo: lo no respaldado sí sale.
|
||||||
|
assert_ok!(Balances::transfer_allow_death(
|
||||||
|
bob_origin(),
|
||||||
|
charlie_account(),
|
||||||
|
saldo - 500
|
||||||
|
));
|
||||||
|
|
||||||
|
// Acabada la corta, el voto largo sigue vivo: nada que liberar.
|
||||||
|
run_to_block(fin_de(corta) + 1);
|
||||||
|
assert_ok!(Governance::unlock_vote_funds(bob_origin(), bob_account()));
|
||||||
|
assert_eq!(congelado_por_votos(&bob_account()), 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Al vencer el voto grande, se libera lo que ya no respalda nada y sigue
|
||||||
|
/// congelado lo que respalda el voto pequeño todavía vivo.
|
||||||
|
#[test]
|
||||||
|
fn al_vencer_el_voto_grande_solo_queda_congelado_el_pequeno_que_sigue_vivo() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let corta = submit_default(alice_origin());
|
||||||
|
let larga = propuesta_con_periodo(11, 3 * VOTING_PERIOD);
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
larga,
|
||||||
|
VoteStance::Aye,
|
||||||
|
300
|
||||||
|
));
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
corta,
|
||||||
|
VoteStance::Aye,
|
||||||
|
500
|
||||||
|
));
|
||||||
|
assert_eq!(congelado_por_votos(&bob_account()), 500);
|
||||||
|
|
||||||
|
run_to_block(fin_de(corta));
|
||||||
|
assert_noop!(
|
||||||
|
Governance::unlock_vote_funds(bob_origin(), bob_account()),
|
||||||
|
Error::<Test>::VoteFundsStillLocked
|
||||||
|
);
|
||||||
|
|
||||||
|
run_to_block(fin_de(corta) + 1);
|
||||||
|
assert_ok!(Governance::unlock_vote_funds(bob_origin(), bob_account()));
|
||||||
|
assert_eq!(congelado_por_votos(&bob_account()), 300);
|
||||||
|
System::assert_last_event(RuntimeEvent::Governance(Event::VoteFundsUnlocked {
|
||||||
|
who: bob_account(),
|
||||||
|
released: 200,
|
||||||
|
still_frozen: 300,
|
||||||
|
}));
|
||||||
|
|
||||||
|
run_to_block(fin_de(larga) + 1);
|
||||||
|
assert_ok!(Governance::unlock_vote_funds(bob_origin(), bob_account()));
|
||||||
|
assert_eq!(congelado_por_votos(&bob_account()), 0);
|
||||||
|
assert!(crate::VoteLocks::<Test>::get(bob_account()).is_empty());
|
||||||
|
System::assert_last_event(RuntimeEvent::Governance(Event::VoteFundsUnlocked {
|
||||||
|
who: bob_account(),
|
||||||
|
released: 300,
|
||||||
|
still_frozen: 0,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// El OGC se libera cuando el voto ya no puede cambiar el resultado: en el último
|
||||||
|
/// bloque del periodo todavía se puede votar, así que sigue congelado.
|
||||||
|
#[test]
|
||||||
|
fn el_ogc_se_libera_solo_cuando_el_voto_ya_no_puede_cambiar_el_resultado() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let id = submit_default(alice_origin());
|
||||||
|
let saldo = Balances::free_balance(bob_account());
|
||||||
|
assert_noop!(
|
||||||
|
Governance::unlock_vote_funds(bob_origin(), bob_account()),
|
||||||
|
Error::<Test>::NoVoteLock
|
||||||
|
);
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
id,
|
||||||
|
VoteStance::Nay,
|
||||||
|
saldo
|
||||||
|
));
|
||||||
|
|
||||||
|
run_to_block(fin_de(id));
|
||||||
|
assert_noop!(
|
||||||
|
Governance::unlock_vote_funds(bob_origin(), bob_account()),
|
||||||
|
Error::<Test>::VoteFundsStillLocked
|
||||||
|
);
|
||||||
|
|
||||||
|
run_to_block(fin_de(id) + 1);
|
||||||
|
assert_ok!(Governance::unlock_vote_funds(bob_origin(), bob_account()));
|
||||||
|
assert_eq!(congelado_por_votos(&bob_account()), 0);
|
||||||
|
// Control positivo: liberado, el OGC se mueve entero.
|
||||||
|
assert_ok!(Balances::transfer_allow_death(
|
||||||
|
bob_origin(),
|
||||||
|
charlie_account(),
|
||||||
|
saldo
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Quien votó con todo su saldo no puede pagar la comisión de su propio
|
||||||
|
/// desbloqueo; por eso cualquiera puede desbloquear un voto vencido ajeno.
|
||||||
|
#[test]
|
||||||
|
fn un_tercero_libera_el_voto_vencido_de_otra_cuenta() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let id = submit_default(alice_origin());
|
||||||
|
let saldo = Balances::free_balance(bob_account());
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
id,
|
||||||
|
VoteStance::Aye,
|
||||||
|
saldo
|
||||||
|
));
|
||||||
|
|
||||||
|
// Control negativo: el tercero no puede liberar un voto vivo.
|
||||||
|
assert_noop!(
|
||||||
|
Governance::unlock_vote_funds(charlie_origin(), bob_account()),
|
||||||
|
Error::<Test>::VoteFundsStillLocked
|
||||||
|
);
|
||||||
|
|
||||||
|
run_to_block(fin_de(id) + 1);
|
||||||
|
assert_ok!(Governance::unlock_vote_funds(
|
||||||
|
charlie_origin(),
|
||||||
|
bob_account()
|
||||||
|
));
|
||||||
|
assert_eq!(congelado_por_votos(&bob_account()), 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Un proponente no puede pedir un periodo casi eterno: con el voto respaldado
|
||||||
|
/// por OGC, eso congelaría casi para siempre el OGC de quien votara.
|
||||||
|
#[test]
|
||||||
|
fn una_propuesta_no_puede_pedir_un_periodo_de_voto_eterno() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
use crate::pallet::{DEFAULT_VOTING_PERIOD_BLOCKS, MAX_VOTING_PERIOD_BLOCKS};
|
||||||
|
assert_eq!(MAX_VOTING_PERIOD_BLOCKS, 2 * DEFAULT_VOTING_PERIOD_BLOCKS);
|
||||||
|
for eterno in [u64::MAX, MAX_VOTING_PERIOD_BLOCKS + 1] {
|
||||||
|
assert_noop!(
|
||||||
|
Governance::submit_proposal(
|
||||||
|
alice_origin(),
|
||||||
|
TITLE_HASH,
|
||||||
|
BODY_HASH,
|
||||||
|
eterno,
|
||||||
|
MIN_PROPOSAL_STAKE,
|
||||||
|
),
|
||||||
|
Error::<Test>::VotingPeriodTooLong
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Control positivo: el máximo exacto se acepta.
|
||||||
|
assert_ok!(Governance::submit_proposal(
|
||||||
|
alice_origin(),
|
||||||
|
TITLE_HASH,
|
||||||
|
BODY_HASH,
|
||||||
|
MAX_VOTING_PERIOD_BLOCKS,
|
||||||
|
MIN_PROPOSAL_STAKE,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Un voto vencido que nadie desbloqueó no revive con el siguiente voto.
|
||||||
|
#[test]
|
||||||
|
fn un_voto_vencido_no_revive_con_el_siguiente() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let corta = submit_default(alice_origin());
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
corta,
|
||||||
|
VoteStance::Aye,
|
||||||
|
500
|
||||||
|
));
|
||||||
|
run_to_block(fin_de(corta) + 1);
|
||||||
|
let nueva = propuesta_con_periodo(12, VOTING_PERIOD);
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
nueva,
|
||||||
|
VoteStance::Aye,
|
||||||
|
1
|
||||||
|
));
|
||||||
|
|
||||||
|
assert_eq!(congelado_por_votos(&bob_account()), 1);
|
||||||
|
let respaldo = crate::VoteLocks::<Test>::get(bob_account());
|
||||||
|
assert_eq!(respaldo.len(), 1);
|
||||||
|
assert_eq!(respaldo[0].proposal, nueva);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// El mismo OGC, ENTERO, vota en dos propuestas (se solapan, como en Polkadot);
|
||||||
|
/// lo que no puede es pesar más que el saldo.
|
||||||
|
#[test]
|
||||||
|
fn el_mismo_ogc_entero_vota_en_dos_propuestas() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let p1 = submit_default(alice_origin());
|
||||||
|
let p2 = propuesta_con_periodo(11, 3 * VOTING_PERIOD);
|
||||||
|
let saldo = Balances::free_balance(bob_account());
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
p1,
|
||||||
|
VoteStance::Aye,
|
||||||
|
saldo
|
||||||
|
));
|
||||||
|
assert_noop!(
|
||||||
|
Governance::cast_vote(bob_origin(), p2, VoteStance::Nay, saldo + 1),
|
||||||
|
Error::<Test>::VoteWeightExceedsBalance
|
||||||
|
);
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
p2,
|
||||||
|
VoteStance::Nay,
|
||||||
|
saldo
|
||||||
|
));
|
||||||
|
assert_eq!(congelado_por_votos(&bob_account()), saldo);
|
||||||
|
assert_eq!(Proposals::<Test>::get(p1).expect("p1").yes_weight, saldo);
|
||||||
|
assert_eq!(Proposals::<Test>::get(p2).expect("p2").nay_weight, saldo);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Vota el OGC LIBRE: lo que está en reserva/hold no suma peso al votar.
|
||||||
|
#[test]
|
||||||
|
fn lo_que_esta_en_reserva_no_vota() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
use frame_support::traits::ReservableCurrency;
|
||||||
|
let id = submit_default(alice_origin());
|
||||||
|
let saldo = Balances::free_balance(bob_account());
|
||||||
|
assert_ok!(<Balances as ReservableCurrency<_>>::reserve(
|
||||||
|
&bob_account(),
|
||||||
|
saldo / 2
|
||||||
|
));
|
||||||
|
let libre = Balances::free_balance(bob_account());
|
||||||
|
assert_noop!(
|
||||||
|
Governance::cast_vote(bob_origin(), id, VoteStance::Aye, libre + 1),
|
||||||
|
Error::<Test>::VoteWeightExceedsBalance
|
||||||
|
);
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
id,
|
||||||
|
VoteStance::Aye,
|
||||||
|
libre
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Un voto de peso 0 cuenta como postura y no toca el respaldo que ya hubiera.
|
||||||
|
#[test]
|
||||||
|
fn un_voto_de_peso_cero_no_toca_el_freeze_previo() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let p1 = submit_default(alice_origin());
|
||||||
|
let p2 = propuesta_con_periodo(11, VOTING_PERIOD);
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
p2,
|
||||||
|
VoteStance::Abstain,
|
||||||
|
0
|
||||||
|
));
|
||||||
|
assert!(Votes::<Test>::contains_key(p2, &bob_account()));
|
||||||
|
assert!(crate::VoteLocks::<Test>::get(bob_account()).is_empty());
|
||||||
|
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
p1,
|
||||||
|
VoteStance::Aye,
|
||||||
|
500
|
||||||
|
));
|
||||||
|
let p3 = propuesta_con_periodo(12, VOTING_PERIOD);
|
||||||
|
assert_ok!(Governance::cast_vote(bob_origin(), p3, VoteStance::Nay, 0));
|
||||||
|
assert_eq!(congelado_por_votos(&bob_account()), 500);
|
||||||
|
assert_eq!(crate::VoteLocks::<Test>::get(bob_account()).len(), 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// La ventana de override dura 14 días (literal, no la propia constante) y se
|
||||||
|
/// cuenta desde el veto que ALCANZA el umbral, no desde el inicio de la
|
||||||
|
/// propuesta ni desde el primer veto. Y su peso también sale del saldo.
|
||||||
|
#[test]
|
||||||
|
fn la_ventana_de_override_dura_14_dias_desde_el_veto_que_alcanza_el_umbral() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
use crate::pallet::CouncilRole;
|
||||||
|
use frame_support::dispatch::RawOrigin;
|
||||||
|
let dave = sp_runtime::AccountId32::new([4u8; 32]);
|
||||||
|
let eve = sp_runtime::AccountId32::new([5u8; 32]);
|
||||||
|
for (m, rol) in [
|
||||||
|
(alice_account(), CouncilRole::Chair),
|
||||||
|
(dave.clone(), CouncilRole::Member),
|
||||||
|
(eve.clone(), CouncilRole::Member),
|
||||||
|
] {
|
||||||
|
assert_ok!(Governance::add_council_member(
|
||||||
|
RawOrigin::Root.into(),
|
||||||
|
m,
|
||||||
|
rol
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let id = submit_default(alice_origin()); // bloque 1
|
||||||
|
run_to_block(10);
|
||||||
|
assert_ok!(Governance::veto_proposal(alice_origin(), id)); // 1 de 2
|
||||||
|
assert!(crate::OverrideDeadline::<Test>::get(id).is_none());
|
||||||
|
run_to_block(60);
|
||||||
|
assert_ok!(Governance::veto_proposal(RuntimeOrigin::signed(dave), id)); // 2 de 2
|
||||||
|
|
||||||
|
let cierre = 60 + 201_600;
|
||||||
|
assert_eq!(crate::OverrideDeadline::<Test>::get(id), Some(cierre));
|
||||||
|
|
||||||
|
let saldo = Balances::free_balance(bob_account());
|
||||||
|
assert_noop!(
|
||||||
|
Governance::override_council_veto(bob_origin(), id, saldo + 1),
|
||||||
|
Error::<Test>::VoteWeightExceedsBalance
|
||||||
|
);
|
||||||
|
run_to_block(cierre + 1);
|
||||||
|
assert_noop!(
|
||||||
|
Governance::override_council_veto(bob_origin(), id, 1),
|
||||||
|
Error::<Test>::OverrideWindowClosed
|
||||||
|
);
|
||||||
|
// Control positivo: en el último bloque de la ventana sí, y congela hasta el cierre.
|
||||||
|
run_to_block(cierre);
|
||||||
|
assert_ok!(Governance::override_council_veto(bob_origin(), id, 1));
|
||||||
|
assert_eq!(congelado_por_votos(&bob_account()), 1);
|
||||||
|
let respaldo = crate::VoteLocks::<Test>::get(bob_account());
|
||||||
|
assert_eq!(respaldo[0].until, cierre);
|
||||||
|
assert_eq!(respaldo[0].kind, crate::BackingKind::Override);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Un veto sin ventana registrada (lo que dejaría una migración mal hecha) no
|
||||||
|
/// admite override: falla cerrado.
|
||||||
|
#[test]
|
||||||
|
fn un_veto_sin_ventana_registrada_no_admite_override() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let id = submit_default(alice_origin());
|
||||||
|
let mut p = Proposals::<Test>::get(id).expect("propuesta");
|
||||||
|
p.status = ProposalStatus::Rejected;
|
||||||
|
Proposals::<Test>::insert(id, p);
|
||||||
|
crate::VetoRejected::<Test>::insert(id, ());
|
||||||
|
assert_noop!(
|
||||||
|
Governance::override_council_veto(bob_origin(), id, 1),
|
||||||
|
Error::<Test>::OverrideWindowClosed
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Una cuenta respalda como mucho `MaxActiveVotes` votos VIVOS (4 en el mock); los
|
||||||
|
/// vencidos no ocupan sitio.
|
||||||
|
#[test]
|
||||||
|
fn el_limite_es_de_votos_vivos_y_los_vencidos_no_ocupan_sitio() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let corta = submit_default(alice_origin());
|
||||||
|
let mut largas = Vec::new();
|
||||||
|
for semilla in 11..15u8 {
|
||||||
|
largas.push(propuesta_con_periodo(semilla, 3 * VOTING_PERIOD));
|
||||||
|
}
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
corta,
|
||||||
|
VoteStance::Aye,
|
||||||
|
10
|
||||||
|
));
|
||||||
|
for id in &largas[..3] {
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
*id,
|
||||||
|
VoteStance::Aye,
|
||||||
|
10
|
||||||
|
));
|
||||||
|
}
|
||||||
|
assert_noop!(
|
||||||
|
Governance::cast_vote(bob_origin(), largas[3], VoteStance::Aye, 10),
|
||||||
|
Error::<Test>::TooManyActiveVotes
|
||||||
|
);
|
||||||
|
// Control positivo: vencida la corta, su sitio queda libre.
|
||||||
|
run_to_block(fin_de(corta) + 1);
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
bob_origin(),
|
||||||
|
largas[3],
|
||||||
|
VoteStance::Aye,
|
||||||
|
10
|
||||||
|
));
|
||||||
|
assert_eq!(crate::VoteLocks::<Test>::get(bob_account()).len(), 4);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -14,17 +14,17 @@
|
|||||||
//! procedimiento completo y el hardware al que hay que creerle).
|
//! procedimiento completo y el hardware al que hay que creerle).
|
||||||
//!
|
//!
|
||||||
//! GENERADO POR SUBSTRATE BENCHMARK CLI VERSION 51.0.0
|
//! GENERADO POR SUBSTRATE BENCHMARK CLI VERSION 51.0.0
|
||||||
//! FECHA: 2026-09-09, STEPS: `50`, REPEAT: `20`
|
//! FECHA: 2026-09-24, STEPS: `50`, REPEAT: `20`
|
||||||
//! HOSTNAME: `MacBookProM3Max.local`, CPU: `<UNKNOWN>`
|
//! HOSTNAME: `MacBookProM3Max.local`, CPU: `<UNKNOWN>`
|
||||||
//! WASM-EXECUTION: `Compiled`, DB CACHE: 1024
|
//! WASM-EXECUTION: `Compiled`, DB CACHE: 1024
|
||||||
|
|
||||||
// Comando ejecutado:
|
// Comando ejecutado:
|
||||||
// /Users/davidherran/.cargo/bin/frame-omni-bencher
|
// frame-omni-bencher
|
||||||
// v1
|
// v1
|
||||||
// benchmark
|
// benchmark
|
||||||
// pallet
|
// pallet
|
||||||
// --runtime
|
// --runtime
|
||||||
// /Users/davidherran/originmetaverse/artifacts/origin-chain/origin_chain_runtime_rv12_bench.compact.compressed.wasm
|
// /Users/davidherran/originmetaverse/external/arkhe-origin-chain/target-bench/release/wbuild/origin-chain-runtime/origin_chain_runtime.compact.compressed.wasm
|
||||||
// --genesis-builder-preset
|
// --genesis-builder-preset
|
||||||
// development
|
// development
|
||||||
// --pallet
|
// --pallet
|
||||||
@@ -78,6 +78,8 @@ pub trait WeightInfo {
|
|||||||
fn treasury_deposit() -> Weight;
|
fn treasury_deposit() -> Weight;
|
||||||
/// Peso de `endorse_emergency_proposal` — MEDIDO sobre el WASM, no estimado a mano.
|
/// Peso de `endorse_emergency_proposal` — MEDIDO sobre el WASM, no estimado a mano.
|
||||||
fn endorse_emergency_proposal() -> Weight;
|
fn endorse_emergency_proposal() -> Weight;
|
||||||
|
/// Peso de `unlock_vote_funds` — MEDIDO sobre el WASM, no estimado a mano.
|
||||||
|
fn unlock_vote_funds() -> Weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Weights parametrizados por el `DbWeight` real del runtime.
|
/// Weights parametrizados por el `DbWeight` real del runtime.
|
||||||
@@ -103,8 +105,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
|||||||
// Proof size en bytes:
|
// Proof size en bytes:
|
||||||
// Medido: `107`
|
// Medido: `107`
|
||||||
// Estimado: `3722`
|
// Estimado: `3722`
|
||||||
// Tiempo minimo de ejecucion: 46_000_000 picosegundos.
|
// Tiempo minimo de ejecucion: 54_000_000 picosegundos.
|
||||||
Weight::from_parts(46_000_000, 0)
|
Weight::from_parts(55_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3722))
|
.saturating_add(Weight::from_parts(0, 3722))
|
||||||
.saturating_add(T::DbWeight::get().reads(7_u64))
|
.saturating_add(T::DbWeight::get().reads(7_u64))
|
||||||
.saturating_add(T::DbWeight::get().writes(5_u64))
|
.saturating_add(T::DbWeight::get().writes(5_u64))
|
||||||
@@ -117,6 +119,12 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
|||||||
/// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
/// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||||
/// Storage: `Governance::Votes` (r:1 w:1)
|
/// Storage: `Governance::Votes` (r:1 w:1)
|
||||||
/// Proof: `Governance::Votes` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `MaxEncodedLen`)
|
/// Proof: `Governance::Votes` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `Governance::VoteLocks` (r:1 w:1)
|
||||||
|
/// Proof: `Governance::VoteLocks` (`max_values`: None, `max_size`: Some(1873), added: 4348, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `Balances::Freezes` (r:1 w:1)
|
||||||
|
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `Balances::Locks` (r:1 w:0)
|
||||||
|
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||||
/// Storage: `System::ExecutionPhase` (r:1 w:0)
|
/// Storage: `System::ExecutionPhase` (r:1 w:0)
|
||||||
/// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
|
/// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
|
||||||
/// Storage: `System::EventCount` (r:1 w:1)
|
/// Storage: `System::EventCount` (r:1 w:1)
|
||||||
@@ -125,20 +133,24 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
|||||||
/// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
/// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||||
fn cast_vote() -> Weight {
|
fn cast_vote() -> Weight {
|
||||||
// Proof size en bytes:
|
// Proof size en bytes:
|
||||||
// Medido: `310`
|
// Medido: `2320`
|
||||||
// Estimado: `3722`
|
// Estimado: `5338`
|
||||||
// Tiempo minimo de ejecucion: 16_000_000 picosegundos.
|
// Tiempo minimo de ejecucion: 46_000_000 picosegundos.
|
||||||
Weight::from_parts(18_000_000, 0)
|
Weight::from_parts(48_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3722))
|
.saturating_add(Weight::from_parts(0, 5338))
|
||||||
.saturating_add(T::DbWeight::get().reads(7_u64))
|
.saturating_add(T::DbWeight::get().reads(10_u64))
|
||||||
.saturating_add(T::DbWeight::get().writes(4_u64))
|
.saturating_add(T::DbWeight::get().writes(6_u64))
|
||||||
}
|
}
|
||||||
/// Storage: `Governance::Proposals` (r:1 w:1)
|
/// Storage: `Governance::Proposals` (r:1 w:1)
|
||||||
/// Proof: `Governance::Proposals` (`max_values`: None, `max_size`: Some(257), added: 2732, mode: `MaxEncodedLen`)
|
/// Proof: `Governance::Proposals` (`max_values`: None, `max_size`: Some(257), added: 2732, mode: `MaxEncodedLen`)
|
||||||
/// Storage: `System::Number` (r:1 w:0)
|
/// Storage: `System::Number` (r:1 w:0)
|
||||||
/// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
/// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||||
/// Storage: `Governance::ProposalBond` (r:1 w:0)
|
/// Storage: `Governance::ProposalBond` (r:1 w:1)
|
||||||
/// Proof: `Governance::ProposalBond` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `MaxEncodedLen`)
|
/// 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: `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)
|
/// Storage: `System::ExecutionPhase` (r:1 w:0)
|
||||||
/// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
|
/// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
|
||||||
/// Storage: `System::EventCount` (r:1 w:1)
|
/// Storage: `System::EventCount` (r:1 w:1)
|
||||||
@@ -147,13 +159,13 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
|||||||
/// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
/// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||||
fn finalize_proposal() -> Weight {
|
fn finalize_proposal() -> Weight {
|
||||||
// Proof size en bytes:
|
// Proof size en bytes:
|
||||||
// Medido: `310`
|
// Medido: `614`
|
||||||
// Estimado: `3722`
|
// Estimado: `6196`
|
||||||
// Tiempo minimo de ejecucion: 13_000_000 picosegundos.
|
// Tiempo minimo de ejecucion: 61_000_000 picosegundos.
|
||||||
Weight::from_parts(14_000_000, 0)
|
Weight::from_parts(62_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3722))
|
.saturating_add(Weight::from_parts(0, 6196))
|
||||||
.saturating_add(T::DbWeight::get().reads(6_u64))
|
.saturating_add(T::DbWeight::get().reads(9_u64))
|
||||||
.saturating_add(T::DbWeight::get().writes(3_u64))
|
.saturating_add(T::DbWeight::get().writes(6_u64))
|
||||||
}
|
}
|
||||||
/// Storage: `Governance::CouncilSize` (r:1 w:1)
|
/// Storage: `Governance::CouncilSize` (r:1 w:1)
|
||||||
/// Proof: `Governance::CouncilSize` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
/// Proof: `Governance::CouncilSize` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||||
@@ -171,8 +183,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
|||||||
// Proof size en bytes:
|
// Proof size en bytes:
|
||||||
// Medido: `25`
|
// Medido: `25`
|
||||||
// Estimado: `3554`
|
// Estimado: `3554`
|
||||||
// Tiempo minimo de ejecucion: 10_000_000 picosegundos.
|
// Tiempo minimo de ejecucion: 12_000_000 picosegundos.
|
||||||
Weight::from_parts(11_000_000, 0)
|
Weight::from_parts(12_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3554))
|
.saturating_add(Weight::from_parts(0, 3554))
|
||||||
.saturating_add(T::DbWeight::get().reads(6_u64))
|
.saturating_add(T::DbWeight::get().reads(6_u64))
|
||||||
.saturating_add(T::DbWeight::get().writes(4_u64))
|
.saturating_add(T::DbWeight::get().writes(4_u64))
|
||||||
@@ -193,43 +205,49 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
|||||||
// Proof size en bytes:
|
// Proof size en bytes:
|
||||||
// Medido: `153`
|
// Medido: `153`
|
||||||
// Estimado: `3554`
|
// Estimado: `3554`
|
||||||
// Tiempo minimo de ejecucion: 11_000_000 picosegundos.
|
// Tiempo minimo de ejecucion: 13_000_000 picosegundos.
|
||||||
Weight::from_parts(12_000_000, 0)
|
Weight::from_parts(14_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3554))
|
.saturating_add(Weight::from_parts(0, 3554))
|
||||||
.saturating_add(T::DbWeight::get().reads(6_u64))
|
.saturating_add(T::DbWeight::get().reads(6_u64))
|
||||||
.saturating_add(T::DbWeight::get().writes(4_u64))
|
.saturating_add(T::DbWeight::get().writes(4_u64))
|
||||||
}
|
}
|
||||||
/// Storage: `Governance::Council` (r:1 w:0)
|
/// Storage: `Governance::Council` (r:5 w:0)
|
||||||
/// Proof: `Governance::Council` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`)
|
/// Proof: `Governance::Council` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`)
|
||||||
/// Storage: `Governance::Proposals` (r:1 w:1)
|
/// Storage: `Governance::Proposals` (r:1 w:1)
|
||||||
/// Proof: `Governance::Proposals` (`max_values`: None, `max_size`: Some(257), added: 2732, mode: `MaxEncodedLen`)
|
/// Proof: `Governance::Proposals` (`max_values`: None, `max_size`: Some(257), added: 2732, mode: `MaxEncodedLen`)
|
||||||
/// Storage: `Governance::CouncilSize` (r:1 w:0)
|
/// Storage: `Governance::CouncilSize` (r:1 w:0)
|
||||||
/// Proof: `Governance::CouncilSize` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
/// Proof: `Governance::CouncilSize` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||||
/// Storage: `Governance::VetoVotes` (r:2 w:1)
|
/// Storage: `Governance::VetoVotes` (r:6 w:1)
|
||||||
/// Proof: `Governance::VetoVotes` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `MaxEncodedLen`)
|
/// 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)
|
/// Storage: `System::Number` (r:1 w:0)
|
||||||
/// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
/// Proof: `System::Number` (`max_values`: Some(1), `max_size`: Some(4), added: 499, 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: `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)
|
/// Storage: `System::ExecutionPhase` (r:1 w:0)
|
||||||
/// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
|
/// Proof: `System::ExecutionPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
|
||||||
/// Storage: `System::EventCount` (r:1 w:1)
|
/// Storage: `System::EventCount` (r:1 w:1)
|
||||||
/// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
/// Proof: `System::EventCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||||
/// Storage: `System::Events` (r:1 w:1)
|
/// Storage: `System::Events` (r:1 w:1)
|
||||||
/// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
/// Proof: `System::Events` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||||
|
/// Storage: `Governance::OverrideDeadline` (r:0 w:1)
|
||||||
|
/// Proof: `Governance::OverrideDeadline` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`)
|
||||||
/// Storage: `Governance::VetoRejected` (r:0 w:1)
|
/// Storage: `Governance::VetoRejected` (r:0 w:1)
|
||||||
/// Proof: `Governance::VetoRejected` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
/// Proof: `Governance::VetoRejected` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
||||||
/// Storage: `Governance::VetoCount` (r:0 w:1)
|
/// Storage: `Governance::VetoCount` (r:0 w:1)
|
||||||
/// Proof: `Governance::VetoCount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
|
/// Proof: `Governance::VetoCount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`)
|
||||||
fn veto_proposal() -> Weight {
|
fn veto_proposal() -> Weight {
|
||||||
// Proof size en bytes:
|
// Proof size en bytes:
|
||||||
// Medido: `435`
|
// Medido: `1440`
|
||||||
// Estimado: `6132`
|
// Estimado: `16416`
|
||||||
// Tiempo minimo de ejecucion: 28_000_000 picosegundos.
|
// Tiempo minimo de ejecucion: 109_000_000 picosegundos.
|
||||||
Weight::from_parts(30_000_000, 0)
|
Weight::from_parts(112_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 6132))
|
.saturating_add(Weight::from_parts(0, 16416))
|
||||||
.saturating_add(T::DbWeight::get().reads(10_u64))
|
.saturating_add(T::DbWeight::get().reads(21_u64))
|
||||||
.saturating_add(T::DbWeight::get().writes(6_u64))
|
.saturating_add(T::DbWeight::get().writes(10_u64))
|
||||||
}
|
}
|
||||||
/// Storage: `Governance::AdvisorFlags` (r:1 w:1)
|
/// Storage: `Governance::AdvisorFlags` (r:1 w:1)
|
||||||
/// Proof: `Governance::AdvisorFlags` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
/// Proof: `Governance::AdvisorFlags` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
||||||
@@ -265,13 +283,13 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
|||||||
// Proof size en bytes:
|
// Proof size en bytes:
|
||||||
// Medido: `98`
|
// Medido: `98`
|
||||||
// Estimado: `3513`
|
// Estimado: `3513`
|
||||||
// Tiempo minimo de ejecucion: 10_000_000 picosegundos.
|
// Tiempo minimo de ejecucion: 11_000_000 picosegundos.
|
||||||
Weight::from_parts(10_000_000, 0)
|
Weight::from_parts(11_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3513))
|
.saturating_add(Weight::from_parts(0, 3513))
|
||||||
.saturating_add(T::DbWeight::get().reads(5_u64))
|
.saturating_add(T::DbWeight::get().reads(5_u64))
|
||||||
.saturating_add(T::DbWeight::get().writes(3_u64))
|
.saturating_add(T::DbWeight::get().writes(3_u64))
|
||||||
}
|
}
|
||||||
/// Storage: `Governance::Proposals` (r:1 w:0)
|
/// Storage: `Governance::Proposals` (r:1 w:1)
|
||||||
/// Proof: `Governance::Proposals` (`max_values`: None, `max_size`: Some(257), added: 2732, mode: `MaxEncodedLen`)
|
/// Proof: `Governance::Proposals` (`max_values`: None, `max_size`: Some(257), added: 2732, mode: `MaxEncodedLen`)
|
||||||
/// Storage: `Governance::VetoRejected` (r:1 w:0)
|
/// Storage: `Governance::VetoRejected` (r:1 w:0)
|
||||||
/// Proof: `Governance::VetoRejected` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
/// Proof: `Governance::VetoRejected` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
||||||
@@ -279,17 +297,33 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
|||||||
/// Proof: `Governance::AdvisorFlags` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
/// Proof: `Governance::AdvisorFlags` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`)
|
||||||
/// Storage: `Governance::OverrideVotes` (r:1 w:1)
|
/// Storage: `Governance::OverrideVotes` (r:1 w:1)
|
||||||
/// Proof: `Governance::OverrideVotes` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`)
|
/// Proof: `Governance::OverrideVotes` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `Governance::OverrideDeadline` (r:1 w:0)
|
||||||
|
/// Proof: `Governance::OverrideDeadline` (`max_values`: None, `max_size`: Some(56), added: 2531, 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::VoteLocks` (r:1 w:1)
|
||||||
|
/// Proof: `Governance::VoteLocks` (`max_values`: None, `max_size`: Some(1873), added: 4348, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `Balances::Freezes` (r:1 w:1)
|
||||||
|
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `Balances::Locks` (r:1 w:0)
|
||||||
|
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, 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::OverrideStakeTotal` (r:1 w:1)
|
/// Storage: `Governance::OverrideStakeTotal` (r:1 w:1)
|
||||||
/// Proof: `Governance::OverrideStakeTotal` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`)
|
/// Proof: `Governance::OverrideStakeTotal` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`)
|
||||||
fn override_council_veto() -> Weight {
|
fn override_council_veto() -> Weight {
|
||||||
// Proof size en bytes:
|
// Proof size en bytes:
|
||||||
// Medido: `361`
|
// Medido: `2468`
|
||||||
// Estimado: `3722`
|
// Estimado: `5338`
|
||||||
// Tiempo minimo de ejecucion: 16_000_000 picosegundos.
|
// Tiempo minimo de ejecucion: 56_000_000 picosegundos.
|
||||||
Weight::from_parts(16_000_000, 0)
|
Weight::from_parts(58_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3722))
|
.saturating_add(Weight::from_parts(0, 5338))
|
||||||
.saturating_add(T::DbWeight::get().reads(5_u64))
|
.saturating_add(T::DbWeight::get().reads(13_u64))
|
||||||
.saturating_add(T::DbWeight::get().writes(2_u64))
|
.saturating_add(T::DbWeight::get().writes(7_u64))
|
||||||
}
|
}
|
||||||
/// Storage: `Governance::Council` (r:1 w:0)
|
/// Storage: `Governance::Council` (r:1 w:0)
|
||||||
/// Proof: `Governance::Council` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`)
|
/// Proof: `Governance::Council` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`)
|
||||||
@@ -317,8 +351,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
|||||||
// Proof size en bytes:
|
// Proof size en bytes:
|
||||||
// Medido: `353`
|
// Medido: `353`
|
||||||
// Estimado: `6132`
|
// Estimado: `6132`
|
||||||
// Tiempo minimo de ejecucion: 60_000_000 picosegundos.
|
// Tiempo minimo de ejecucion: 68_000_000 picosegundos.
|
||||||
Weight::from_parts(61_000_000, 0)
|
Weight::from_parts(69_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 6132))
|
.saturating_add(Weight::from_parts(0, 6132))
|
||||||
.saturating_add(T::DbWeight::get().reads(11_u64))
|
.saturating_add(T::DbWeight::get().reads(11_u64))
|
||||||
.saturating_add(T::DbWeight::get().writes(6_u64))
|
.saturating_add(T::DbWeight::get().writes(6_u64))
|
||||||
@@ -343,8 +377,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
|||||||
// Proof size en bytes:
|
// Proof size en bytes:
|
||||||
// Medido: `494`
|
// Medido: `494`
|
||||||
// Estimado: `6196`
|
// Estimado: `6196`
|
||||||
// Tiempo minimo de ejecucion: 51_000_000 picosegundos.
|
// Tiempo minimo de ejecucion: 56_000_000 picosegundos.
|
||||||
Weight::from_parts(52_000_000, 0)
|
Weight::from_parts(58_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 6196))
|
.saturating_add(Weight::from_parts(0, 6196))
|
||||||
.saturating_add(T::DbWeight::get().reads(9_u64))
|
.saturating_add(T::DbWeight::get().reads(9_u64))
|
||||||
.saturating_add(T::DbWeight::get().writes(5_u64))
|
.saturating_add(T::DbWeight::get().writes(5_u64))
|
||||||
@@ -365,8 +399,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
|||||||
// Proof size en bytes:
|
// Proof size en bytes:
|
||||||
// Medido: `101`
|
// Medido: `101`
|
||||||
// Estimado: `3593`
|
// Estimado: `3593`
|
||||||
// Tiempo minimo de ejecucion: 38_000_000 picosegundos.
|
// Tiempo minimo de ejecucion: 43_000_000 picosegundos.
|
||||||
Weight::from_parts(42_000_000, 0)
|
Weight::from_parts(43_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3593))
|
.saturating_add(Weight::from_parts(0, 3593))
|
||||||
.saturating_add(T::DbWeight::get().reads(6_u64))
|
.saturating_add(T::DbWeight::get().reads(6_u64))
|
||||||
.saturating_add(T::DbWeight::get().writes(3_u64))
|
.saturating_add(T::DbWeight::get().writes(3_u64))
|
||||||
@@ -389,51 +423,77 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
|||||||
// Proof size en bytes:
|
// Proof size en bytes:
|
||||||
// Medido: `153`
|
// Medido: `153`
|
||||||
// Estimado: `6132`
|
// Estimado: `6132`
|
||||||
// Tiempo minimo de ejecucion: 20_000_000 picosegundos.
|
// Tiempo minimo de ejecucion: 22_000_000 picosegundos.
|
||||||
Weight::from_parts(21_000_000, 0)
|
Weight::from_parts(23_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 6132))
|
.saturating_add(Weight::from_parts(0, 6132))
|
||||||
.saturating_add(T::DbWeight::get().reads(8_u64))
|
.saturating_add(T::DbWeight::get().reads(8_u64))
|
||||||
.saturating_add(T::DbWeight::get().writes(3_u64))
|
.saturating_add(T::DbWeight::get().writes(3_u64))
|
||||||
}
|
}
|
||||||
|
/// Storage: `Governance::VoteLocks` (r:1 w:1)
|
||||||
|
/// Proof: `Governance::VoteLocks` (`max_values`: None, `max_size`: Some(1873), added: 4348, 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: `Balances::Freezes` (r:1 w:1)
|
||||||
|
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `System::Account` (r:1 w:1)
|
||||||
|
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `Balances::Locks` (r:1 w:0)
|
||||||
|
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, 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 unlock_vote_funds() -> Weight {
|
||||||
|
// Proof size en bytes:
|
||||||
|
// Medido: `2197`
|
||||||
|
// Estimado: `5338`
|
||||||
|
// Tiempo minimo de ejecucion: 34_000_000 picosegundos.
|
||||||
|
Weight::from_parts(40_000_000, 0)
|
||||||
|
.saturating_add(Weight::from_parts(0, 5338))
|
||||||
|
.saturating_add(T::DbWeight::get().reads(8_u64))
|
||||||
|
.saturating_add(T::DbWeight::get().writes(5_u64))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Impl para mocks y tests — `RocksDbWeight` directo, sin necesitar `T`.
|
/// Impl para mocks y tests — `RocksDbWeight` directo, sin necesitar `T`.
|
||||||
impl WeightInfo for () {
|
impl WeightInfo for () {
|
||||||
fn submit_proposal() -> Weight {
|
fn submit_proposal() -> Weight {
|
||||||
Weight::from_parts(46_000_000, 0)
|
Weight::from_parts(55_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3722))
|
.saturating_add(Weight::from_parts(0, 3722))
|
||||||
.saturating_add(RocksDbWeight::get().reads(7_u64))
|
.saturating_add(RocksDbWeight::get().reads(7_u64))
|
||||||
.saturating_add(RocksDbWeight::get().writes(5_u64))
|
.saturating_add(RocksDbWeight::get().writes(5_u64))
|
||||||
}
|
}
|
||||||
fn cast_vote() -> Weight {
|
fn cast_vote() -> Weight {
|
||||||
Weight::from_parts(18_000_000, 0)
|
Weight::from_parts(48_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3722))
|
.saturating_add(Weight::from_parts(0, 5338))
|
||||||
.saturating_add(RocksDbWeight::get().reads(7_u64))
|
.saturating_add(RocksDbWeight::get().reads(10_u64))
|
||||||
.saturating_add(RocksDbWeight::get().writes(4_u64))
|
.saturating_add(RocksDbWeight::get().writes(6_u64))
|
||||||
}
|
}
|
||||||
fn finalize_proposal() -> Weight {
|
fn finalize_proposal() -> Weight {
|
||||||
Weight::from_parts(14_000_000, 0)
|
Weight::from_parts(62_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3722))
|
.saturating_add(Weight::from_parts(0, 6196))
|
||||||
.saturating_add(RocksDbWeight::get().reads(6_u64))
|
.saturating_add(RocksDbWeight::get().reads(9_u64))
|
||||||
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
.saturating_add(RocksDbWeight::get().writes(6_u64))
|
||||||
}
|
}
|
||||||
fn add_council_member() -> Weight {
|
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)
|
Weight::from_parts(12_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3554))
|
.saturating_add(Weight::from_parts(0, 3554))
|
||||||
.saturating_add(RocksDbWeight::get().reads(6_u64))
|
.saturating_add(RocksDbWeight::get().reads(6_u64))
|
||||||
.saturating_add(RocksDbWeight::get().writes(4_u64))
|
.saturating_add(RocksDbWeight::get().writes(4_u64))
|
||||||
}
|
}
|
||||||
|
fn remove_council_member() -> Weight {
|
||||||
|
Weight::from_parts(14_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 {
|
fn veto_proposal() -> Weight {
|
||||||
Weight::from_parts(30_000_000, 0)
|
Weight::from_parts(112_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 6132))
|
.saturating_add(Weight::from_parts(0, 16416))
|
||||||
.saturating_add(RocksDbWeight::get().reads(10_u64))
|
.saturating_add(RocksDbWeight::get().reads(21_u64))
|
||||||
.saturating_add(RocksDbWeight::get().writes(6_u64))
|
.saturating_add(RocksDbWeight::get().writes(10_u64))
|
||||||
}
|
}
|
||||||
fn mark_as_advisor() -> Weight {
|
fn mark_as_advisor() -> Weight {
|
||||||
Weight::from_parts(10_000_000, 0)
|
Weight::from_parts(10_000_000, 0)
|
||||||
@@ -442,41 +502,47 @@ impl WeightInfo for () {
|
|||||||
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
||||||
}
|
}
|
||||||
fn unmark_as_advisor() -> Weight {
|
fn unmark_as_advisor() -> Weight {
|
||||||
Weight::from_parts(10_000_000, 0)
|
Weight::from_parts(11_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3513))
|
.saturating_add(Weight::from_parts(0, 3513))
|
||||||
.saturating_add(RocksDbWeight::get().reads(5_u64))
|
.saturating_add(RocksDbWeight::get().reads(5_u64))
|
||||||
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
||||||
}
|
}
|
||||||
fn override_council_veto() -> Weight {
|
fn override_council_veto() -> Weight {
|
||||||
Weight::from_parts(16_000_000, 0)
|
Weight::from_parts(58_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3722))
|
.saturating_add(Weight::from_parts(0, 5338))
|
||||||
.saturating_add(RocksDbWeight::get().reads(5_u64))
|
.saturating_add(RocksDbWeight::get().reads(13_u64))
|
||||||
.saturating_add(RocksDbWeight::get().writes(2_u64))
|
.saturating_add(RocksDbWeight::get().writes(7_u64))
|
||||||
}
|
}
|
||||||
fn submit_emergency_proposal() -> Weight {
|
fn submit_emergency_proposal() -> Weight {
|
||||||
Weight::from_parts(61_000_000, 0)
|
Weight::from_parts(69_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 6132))
|
.saturating_add(Weight::from_parts(0, 6132))
|
||||||
.saturating_add(RocksDbWeight::get().reads(11_u64))
|
.saturating_add(RocksDbWeight::get().reads(11_u64))
|
||||||
.saturating_add(RocksDbWeight::get().writes(6_u64))
|
.saturating_add(RocksDbWeight::get().writes(6_u64))
|
||||||
}
|
}
|
||||||
fn treasury_disbursement() -> Weight {
|
fn treasury_disbursement() -> Weight {
|
||||||
Weight::from_parts(52_000_000, 0)
|
Weight::from_parts(58_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 6196))
|
.saturating_add(Weight::from_parts(0, 6196))
|
||||||
.saturating_add(RocksDbWeight::get().reads(9_u64))
|
.saturating_add(RocksDbWeight::get().reads(9_u64))
|
||||||
.saturating_add(RocksDbWeight::get().writes(5_u64))
|
.saturating_add(RocksDbWeight::get().writes(5_u64))
|
||||||
}
|
}
|
||||||
fn treasury_deposit() -> Weight {
|
fn treasury_deposit() -> Weight {
|
||||||
Weight::from_parts(42_000_000, 0)
|
Weight::from_parts(43_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3593))
|
.saturating_add(Weight::from_parts(0, 3593))
|
||||||
.saturating_add(RocksDbWeight::get().reads(6_u64))
|
.saturating_add(RocksDbWeight::get().reads(6_u64))
|
||||||
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
||||||
}
|
}
|
||||||
fn endorse_emergency_proposal() -> Weight {
|
fn endorse_emergency_proposal() -> Weight {
|
||||||
Weight::from_parts(21_000_000, 0)
|
Weight::from_parts(23_000_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 6132))
|
.saturating_add(Weight::from_parts(0, 6132))
|
||||||
.saturating_add(RocksDbWeight::get().reads(8_u64))
|
.saturating_add(RocksDbWeight::get().reads(8_u64))
|
||||||
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
||||||
}
|
}
|
||||||
|
fn unlock_vote_funds() -> Weight {
|
||||||
|
Weight::from_parts(40_000_000, 0)
|
||||||
|
.saturating_add(Weight::from_parts(0, 5338))
|
||||||
|
.saturating_add(RocksDbWeight::get().reads(8_u64))
|
||||||
|
.saturating_add(RocksDbWeight::get().writes(5_u64))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -517,6 +583,7 @@ mod guard {
|
|||||||
("treasury_disbursement", <() as WeightInfo>::treasury_disbursement()),
|
("treasury_disbursement", <() as WeightInfo>::treasury_disbursement()),
|
||||||
("treasury_deposit", <() as WeightInfo>::treasury_deposit()),
|
("treasury_deposit", <() as WeightInfo>::treasury_deposit()),
|
||||||
("endorse_emergency_proposal", <() as WeightInfo>::endorse_emergency_proposal()),
|
("endorse_emergency_proposal", <() as WeightInfo>::endorse_emergency_proposal()),
|
||||||
|
("unlock_vote_funds", <() as WeightInfo>::unlock_vote_funds()),
|
||||||
];
|
];
|
||||||
for (nombre, w) in casos {
|
for (nombre, w) in casos {
|
||||||
assert!(
|
assert!(
|
||||||
|
|||||||
@@ -531,6 +531,11 @@ parameter_types! {
|
|||||||
impl origin_chain_governance::Config for Runtime {
|
impl origin_chain_governance::Config for Runtime {
|
||||||
type RuntimeEvent = RuntimeEvent;
|
type RuntimeEvent = RuntimeEvent;
|
||||||
type Currency = crate::Balances;
|
type Currency = crate::Balances;
|
||||||
|
// RV15: el OGC que respalda un voto queda congelado (freeze) mientras el voto
|
||||||
|
// pueda cambiar un resultado. `MaxFreezes` de Balances cuenta sola la variante.
|
||||||
|
type RuntimeFreezeReason = RuntimeFreezeReason;
|
||||||
|
// RV15: votos VIVOS simultáneos por cuenta (los vencidos se descartan solos).
|
||||||
|
type MaxActiveVotes = frame_support::traits::ConstU32<32>;
|
||||||
type TreasuryPalletId = GovernanceTreasuryPalletId;
|
type TreasuryPalletId = GovernanceTreasuryPalletId;
|
||||||
// Weights INTERIM hand-derived DB-aware (ver weights.rs). Regenerable en HW.
|
// Weights INTERIM hand-derived DB-aware (ver weights.rs). Regenerable en HW.
|
||||||
type WeightInfo = origin_chain_governance::weights::SubstrateWeight<Runtime>;
|
type WeightInfo = origin_chain_governance::weights::SubstrateWeight<Runtime>;
|
||||||
|
|||||||
@@ -604,4 +604,76 @@ mod tests {
|
|||||||
"el pool og/ecosy debe tener exactamente los 400M que la emisión libera"
|
"el pool og/ecosy debe tener exactamente los 400M que la emisión libera"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// RV15 con la configuración REAL del runtime (no el mock): un voto congela su
|
||||||
|
/// OGC en `pallet-balances`, lo congelado no sale, y vencido el voto un TERCERO
|
||||||
|
/// lo libera. Sin este test, un cambio de configuración (por ejemplo
|
||||||
|
/// `MaxFreezes = 0`) haría fallar en producción todo voto con peso sin que
|
||||||
|
/// ningún test del pallet lo viera (revisión adversaria de RV15).
|
||||||
|
#[test]
|
||||||
|
fn un_voto_congela_ogc_con_la_configuracion_real_del_runtime() {
|
||||||
|
use crate::{Balances, Governance, RuntimeFreezeReason, RuntimeOrigin, System};
|
||||||
|
use frame_support::assert_ok;
|
||||||
|
use frame_support::traits::fungible::{Inspect, InspectFreeze};
|
||||||
|
use origin_chain_governance::{FreezeReason, MIN_PROPOSAL_STAKE};
|
||||||
|
use origin_chain_types::VoteStance;
|
||||||
|
|
||||||
|
let json = get_preset(&PresetId::from(PRESET_LOCAL_TESTNET)).expect("preset");
|
||||||
|
let mut ext = sp_io::TestExternalities::new_empty();
|
||||||
|
ext.execute_with(|| {
|
||||||
|
frame_support::genesis_builder_helper::build_state::<RuntimeGenesisConfig>(json)
|
||||||
|
.expect("el preset construye estado");
|
||||||
|
System::set_block_number(1);
|
||||||
|
let alice = account_from_sr25519(ALICE_SR25519);
|
||||||
|
let bob = account_from_sr25519(BOB_SR25519);
|
||||||
|
let charlie = account_from_sr25519(CHARLIE_SR25519);
|
||||||
|
|
||||||
|
let (titulo, cuerpo, periodo) = ([1u8; 32], [2u8; 32], 100u64);
|
||||||
|
assert_ok!(Governance::submit_proposal(
|
||||||
|
RuntimeOrigin::signed(alice.clone()),
|
||||||
|
titulo,
|
||||||
|
cuerpo,
|
||||||
|
periodo,
|
||||||
|
MIN_PROPOSAL_STAKE,
|
||||||
|
));
|
||||||
|
let id = origin_chain_governance::derive_proposal_id(
|
||||||
|
&origin_chain_types::AccountId::new(ALICE_SR25519),
|
||||||
|
&titulo,
|
||||||
|
&cuerpo,
|
||||||
|
);
|
||||||
|
|
||||||
|
let saldo = Balances::balance(&bob);
|
||||||
|
assert!(saldo > 0, "el preset local debe fondear a Bob");
|
||||||
|
assert_ok!(Governance::cast_vote(
|
||||||
|
RuntimeOrigin::signed(bob.clone()),
|
||||||
|
id,
|
||||||
|
VoteStance::Aye,
|
||||||
|
saldo,
|
||||||
|
));
|
||||||
|
let razon: RuntimeFreezeReason = FreezeReason::GovernanceVote.into();
|
||||||
|
assert_eq!(Balances::balance_frozen(&razon, &bob), saldo);
|
||||||
|
assert!(
|
||||||
|
Balances::transfer_allow_death(
|
||||||
|
RuntimeOrigin::signed(bob.clone()),
|
||||||
|
charlie.clone().into(),
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
.is_err(),
|
||||||
|
"salió OGC congelado por un voto vivo"
|
||||||
|
);
|
||||||
|
|
||||||
|
System::set_block_number(1 + periodo as u32 + 1);
|
||||||
|
assert_ok!(Governance::unlock_vote_funds(
|
||||||
|
RuntimeOrigin::signed(charlie.clone()),
|
||||||
|
bob.clone(),
|
||||||
|
));
|
||||||
|
assert_eq!(Balances::balance_frozen(&razon, &bob), 0);
|
||||||
|
// Control positivo: liberado, el OGC vuelve a moverse.
|
||||||
|
assert_ok!(Balances::transfer_allow_death(
|
||||||
|
RuntimeOrigin::signed(bob),
|
||||||
|
charlie.into(),
|
||||||
|
1,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1019,7 +1019,7 @@ pub const VERSION: sp_version::RuntimeVersion = sp_version::RuntimeVersion {
|
|||||||
spec_name: alloc::borrow::Cow::Borrowed("origin-chain"),
|
spec_name: alloc::borrow::Cow::Borrowed("origin-chain"),
|
||||||
impl_name: alloc::borrow::Cow::Borrowed("origin-chain-charon"),
|
impl_name: alloc::borrow::Cow::Borrowed("origin-chain-charon"),
|
||||||
authoring_version: 1,
|
authoring_version: 1,
|
||||||
spec_version: 14,
|
spec_version: 15,
|
||||||
impl_version: 1,
|
impl_version: 1,
|
||||||
apis: RUNTIME_API_VERSIONS,
|
apis: RUNTIME_API_VERSIONS,
|
||||||
transaction_version: 1,
|
transaction_version: 1,
|
||||||
@@ -1087,7 +1087,7 @@ mod tests {
|
|||||||
/// mismo commit en que la version subio a 12.
|
/// mismo commit en que la version subio a 12.
|
||||||
#[test]
|
#[test]
|
||||||
fn spec_version_vigente_y_transaction_version_intacta() {
|
fn spec_version_vigente_y_transaction_version_intacta() {
|
||||||
assert_eq!(RUNTIME_VERSION, 14);
|
assert_eq!(RUNTIME_VERSION, 15);
|
||||||
assert_eq!(TRANSACTION_VERSION, 1);
|
assert_eq!(TRANSACTION_VERSION, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,13 @@
|
|||||||
# QUE HACE
|
# QUE HACE
|
||||||
# ────────
|
# ────────
|
||||||
# 1. Construye el runtime WASM con `runtime-benchmarks`.
|
# 1. Construye el runtime WASM con `runtime-benchmarks`.
|
||||||
# 2. Corre `frame-omni-bencher` sobre ESE blob (el mismo que se despliega).
|
# 2. Corre `frame-omni-bencher` sobre ESE blob. OJO: NO es el que se despliega.
|
||||||
|
# Lleva `runtime-benchmarks` (expone la runtime API Benchmark: superficie de DoS
|
||||||
|
# en los nodos RPC). Lo que tiene que coincidir con lo desplegado es el COMMIT,
|
||||||
|
# no el blob. Por eso se construye en su propio target (`target-bench/`) y nunca
|
||||||
|
# en `target/release/wbuild`, que es de donde sale el blob de un set_code.
|
||||||
|
# (Corregido en RV15: la revisión adversaria encontró el blob de bench en la
|
||||||
|
# ruta de despliegue, justo después de regenerar pesos.)
|
||||||
# 3. Reescribe los 5 `weights.rs` con la plantilla de la casa, que emite
|
# 3. Reescribe los 5 `weights.rs` con la plantilla de la casa, que emite
|
||||||
# trait + SubstrateWeight<T> + () + un guard generado que reprueba cualquier
|
# trait + SubstrateWeight<T> + () + un guard generado que reprueba cualquier
|
||||||
# proof_size = 0.
|
# proof_size = 0.
|
||||||
@@ -41,10 +47,15 @@ ROOT="$PWD"
|
|||||||
STEPS="${STEPS:-50}"
|
STEPS="${STEPS:-50}"
|
||||||
REPEAT="${REPEAT:-20}"
|
REPEAT="${REPEAT:-20}"
|
||||||
BENCHER="${BENCHER:-frame-omni-bencher}"
|
BENCHER="${BENCHER:-frame-omni-bencher}"
|
||||||
WASM="${WASM:-$ROOT/target/release/wbuild/origin-chain-runtime/origin_chain_runtime.compact.compressed.wasm}"
|
# DENTRO del repo, no en /tmp: substrate-wasm-builder busca el Cargo.lock subiendo
|
||||||
# SKIP_BUILD=1 mide un blob YA construido. Es el modo del banco de referencia:
|
# desde el target. Fuera del workspace no lo encuentra, resuelve dependencias desde
|
||||||
# el Pi 5 no compila Substrate, se le lleva el blob que se va a desplegar — asi
|
# cero y trae crates que exigen otro rustc (medido en RV15).
|
||||||
# el binario medido y el desplegado son el MISMO, que es la condicion de Laurha.
|
BENCH_TARGET="${BENCH_TARGET:-$ROOT/target-bench}"
|
||||||
|
WASM="${WASM:-$BENCH_TARGET/release/wbuild/origin-chain-runtime/origin_chain_runtime.compact.compressed.wasm}"
|
||||||
|
# SKIP_BUILD=1 mide un blob de bench YA construido. Es el modo del banco de
|
||||||
|
# referencia: el Pi 5 no compila Substrate, se le lleva el blob de bench del MISMO
|
||||||
|
# COMMIT que se va a desplegar. La condicion de Laurha (medir lo que se despliega)
|
||||||
|
# se cumple por commit: el blob desplegado es el mismo codigo SIN runtime-benchmarks.
|
||||||
|
|
||||||
command -v "$BENCHER" >/dev/null || { echo "falta $BENCHER — ver cabecera"; exit 1; }
|
command -v "$BENCHER" >/dev/null || { echo "falta $BENCHER — ver cabecera"; exit 1; }
|
||||||
"$BENCHER" --version | grep -q "0\.15\.0" || echo "⚠ el bencher NO es 0.15.0; si falla al decodificar TrackedStorageKey, es esto"
|
"$BENCHER" --version | grep -q "0\.15\.0" || echo "⚠ el bencher NO es 0.15.0; si falla al decodificar TrackedStorageKey, es esto"
|
||||||
@@ -53,7 +64,8 @@ if [ "${SKIP_BUILD:-0}" = "1" ]; then
|
|||||||
echo "═══ 1/2 SALTADO — midiendo blob ya construido ═══"
|
echo "═══ 1/2 SALTADO — midiendo blob ya construido ═══"
|
||||||
else
|
else
|
||||||
echo "═══ 1/2 construyendo el WASM con runtime-benchmarks ═══"
|
echo "═══ 1/2 construyendo el WASM con runtime-benchmarks ═══"
|
||||||
WASM_BUILD_STD=0 cargo build --release -p origin-chain-runtime --features wasm-build,runtime-benchmarks
|
CARGO_TARGET_DIR="$BENCH_TARGET" WASM_BUILD_STD=0 \
|
||||||
|
cargo build --release -p origin-chain-runtime --features wasm-build,runtime-benchmarks
|
||||||
fi
|
fi
|
||||||
echo "blob: $( (shasum -a 256 "$WASM" 2>/dev/null || sha256sum "$WASM") | cut -d' ' -f1)"
|
echo "blob: $( (shasum -a 256 "$WASM" 2>/dev/null || sha256sum "$WASM") | cut -d' ' -f1)"
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user