Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 60 additions & 2 deletions rs/nns/governance/src/governance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1316,14 +1316,20 @@ impl Governance {
cmc: Arc<dyn CMC>,
mut randomness: Box<dyn RandomnessGenerator>,
) -> Self {
let (heap_governance_proto, maybe_rng_seed) = split_governance_proto(governance_proto);
let (mut heap_governance_proto, maybe_rng_seed) = split_governance_proto(governance_proto);

// Carry over the previous rng seed to avoid race conditions in handling queued ingress
// messages that may require a functioning RNG.
if let Some(rng_seed) = maybe_rng_seed {
randomness.seed_rng(rng_seed);
}

// Migration: reduce neuron_minimum_dissolve_delay_to_vote_seconds to 2 weeks if it is
// currently higher, per the mission70 whitepaper.
Self::maybe_reduce_neuron_minimum_dissolve_delay_to_vote_seconds(
&mut heap_governance_proto,
);

let mut governance = Self {
heap_data: heap_governance_proto,
neuron_store: NeuronStore::new_restored(),
Expand Down Expand Up @@ -4780,9 +4786,61 @@ impl Governance {
}

pub fn neuron_minimum_dissolve_delay_to_vote_seconds(&self) -> u64 {
let default = if is_mission_70_voting_rewards_enabled() {
14 * ONE_DAY_SECONDS
} else {
VotingPowerEconomics::DEFAULT_NEURON_MINIMUM_DISSOLVE_DELAY_TO_VOTE_SECONDS
Comment on lines 4790 to 4792
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is weird to me that in one case, you have a * expression, but in the other, you have a dedicated constant. Well, I guess this doesn't matter very much, because this code is temporary anyway.

};
self.voting_power_economics()
.neuron_minimum_dissolve_delay_to_vote_seconds
.unwrap_or(VotingPowerEconomics::DEFAULT_NEURON_MINIMUM_DISSOLVE_DELAY_TO_VOTE_SECONDS)
.unwrap_or(default)
}

/// Reduces `neuron_minimum_dissolve_delay_to_vote_seconds` to 2 weeks if it is currently
/// higher. This is a one-time migration that takes effect on the first post_upgrade after
/// this code is deployed.
fn maybe_reduce_neuron_minimum_dissolve_delay_to_vote_seconds(
heap_data: &mut HeapGovernanceData,
) {
if !is_mission_70_voting_rewards_enabled() {
return;
}

let two_weeks_seconds = 14 * ONE_DAY_SECONDS;

let Some(voting_power_economics) = heap_data
.economics
.as_mut()
.and_then(|economics| economics.voting_power_economics.as_mut())
else {
println!(
"{}WARNING: Cannot migrate neuron_minimum_dissolve_delay_to_vote_seconds: \
voting_power_economics not set.",
LOG_PREFIX,
);
return;
};

let current = voting_power_economics
.neuron_minimum_dissolve_delay_to_vote_seconds
.unwrap_or(VotingPowerEconomics::DEFAULT_NEURON_MINIMUM_DISSOLVE_DELAY_TO_VOTE_SECONDS);

assert!(
current >= two_weeks_seconds,
"neuron_minimum_dissolve_delay_to_vote_seconds ({}) is unexpectedly below 2 weeks ({})",
current,
two_weeks_seconds,
);

if current > two_weeks_seconds {
println!(
"{}Migrating neuron_minimum_dissolve_delay_to_vote_seconds from {} to {} \
(2 weeks).",
LOG_PREFIX, current, two_weeks_seconds,
);
voting_power_economics.neuron_minimum_dissolve_delay_to_vote_seconds =
Some(two_weeks_seconds);
}
}

/// The proposal id of the next proposal.
Expand Down
55 changes: 54 additions & 1 deletion rs/nns/governance/src/governance/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use crate::{
test_utils::{MockEnvironment, StubCMC, StubIcpLedger},
};
use ic_base_types::PrincipalId;
use ic_nervous_system_common::{E8, assert_is_err, assert_is_ok};
use ic_nervous_system_common::{
E8, ONE_DAY_SECONDS, ONE_MONTH_SECONDS, assert_is_err, assert_is_ok,
};
#[cfg(feature = "test")]
use ic_nervous_system_proto::pb::v1::GlobalTimeOfDay;
use ic_nns_common::pb::v1::NeuronId;
Expand Down Expand Up @@ -1799,3 +1801,54 @@ fn test_maybe_set_eight_year_gang_bonus_base() {
.unwrap();
assert_eq!(bonus, 140 * E8);
}

#[test]
fn test_post_upgrade_migrates_neuron_minimum_dissolve_delay_to_vote_seconds() {
let _mission70 = crate::temporarily_enable_mission_70_voting_rewards();
let two_weeks_seconds = 14 * ONE_DAY_SECONDS;

// Simulate the old production state: 6 months.
let mut heap_data = HeapGovernanceData {
economics: Some(NetworkEconomics {
voting_power_economics: Some(VotingPowerEconomics {
neuron_minimum_dissolve_delay_to_vote_seconds: Some(6 * ONE_MONTH_SECONDS),
..VotingPowerEconomics::with_default_values()
}),
..NetworkEconomics::with_default_values()
}),
..Default::default()
};

Governance::maybe_reduce_neuron_minimum_dissolve_delay_to_vote_seconds(&mut heap_data);

let actual = heap_data
.economics
.as_ref()
.unwrap()
.voting_power_economics
.as_ref()
.unwrap()
.neuron_minimum_dissolve_delay_to_vote_seconds;
assert_eq!(actual, Some(two_weeks_seconds));
}

#[test]
#[should_panic(expected = "unexpectedly below 2 weeks")]
fn test_post_upgrade_panics_if_neuron_minimum_dissolve_delay_to_vote_seconds_below_two_weeks() {
let _mission70 = crate::temporarily_enable_mission_70_voting_rewards();
let one_week_seconds = 7 * ONE_DAY_SECONDS;

let mut heap_data = HeapGovernanceData {
economics: Some(NetworkEconomics {
voting_power_economics: Some(VotingPowerEconomics {
neuron_minimum_dissolve_delay_to_vote_seconds: Some(one_week_seconds),
..VotingPowerEconomics::with_default_values()
}),
..NetworkEconomics::with_default_values()
}),
..Default::default()
};

// Should panic because the value is below 2 weeks.
Governance::maybe_reduce_neuron_minimum_dissolve_delay_to_vote_seconds(&mut heap_data);
}
6 changes: 3 additions & 3 deletions rs/nns/governance/src/network_economics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ impl VotingPowerEconomics {
/// which originate from the time when the minimum dissolve delay to vote was an internal NNS
/// constant.
pub const NEURON_MINIMUM_DISSOLVE_DELAY_TO_VOTE_SECONDS_BOUNDS: RangeInclusive<u64> =
(3 * ONE_MONTH_SECONDS)..=(6 * ONE_MONTH_SECONDS);
(14 * ONE_DAY_SECONDS)..=(6 * ONE_MONTH_SECONDS);

pub const DEFAULT_START_REDUCING_VOTING_POWER_AFTER_SECONDS: u64 = 6 * ONE_MONTH_SECONDS;

Expand Down Expand Up @@ -369,8 +369,8 @@ impl VotingPowerEconomics {
.contains(&delay)
{
let defect = format!(
"neuron_minimum_dissolve_delay_to_vote_seconds ({:?}) must be between three \
and six months.",
"neuron_minimum_dissolve_delay_to_vote_seconds ({:?}) must be between two \
weeks and six months.",
self.neuron_minimum_dissolve_delay_to_vote_seconds
);
defects.push(defect);
Expand Down
8 changes: 4 additions & 4 deletions rs/nns/governance/src/network_economics_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ fn test_network_economics_with_default_values_is_valid() {
#[test]
fn test_neuron_minimum_dissolve_delay_to_vote_seconds_bounds() {
// Define constants for better readability and maintainability
const LOWER_BOUND_SECONDS: u64 = 3 * ONE_MONTH_SECONDS;
const LOWER_BOUND_SECONDS: u64 = 14 * ONE_DAY_SECONDS;
const UPPER_BOUND_SECONDS: u64 = 6 * ONE_MONTH_SECONDS;
const DEFAULT_SECONDS: u64 = LOWER_BOUND_SECONDS; // Assuming default is the minimum
const DEFAULT_SECONDS: u64 = UPPER_BOUND_SECONDS;

// Test cases: (delay in seconds, expected result)
let test_cases = [
Expand All @@ -106,14 +106,14 @@ fn test_neuron_minimum_dissolve_delay_to_vote_seconds_bounds() {
(
Some(LOWER_BOUND_SECONDS - 1),
Err(vec![format!(
"neuron_minimum_dissolve_delay_to_vote_seconds (Some({})) must be between three and six months.",
"neuron_minimum_dissolve_delay_to_vote_seconds (Some({})) must be between two weeks and six months.",
LOWER_BOUND_SECONDS - 1
)]),
),
(
Some(UPPER_BOUND_SECONDS + 1),
Err(vec![format!(
"neuron_minimum_dissolve_delay_to_vote_seconds (Some({})) must be between three and six months.",
"neuron_minimum_dissolve_delay_to_vote_seconds (Some({})) must be between two weeks and six months.",
UPPER_BOUND_SECONDS + 1
)]),
),
Expand Down
8 changes: 7 additions & 1 deletion rs/nns/governance/src/neuron_store/voting_power.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use ic_nns_governance_api::Vote;
use super::{NeuronStore, NeuronStoreError};

use crate::{
is_mission_70_voting_rewards_enabled,
neuron::Neuron,
pb::v1::{Ballot, NeuronIdToVotingPowerMap, VotingPowerEconomics, VotingPowerTotal},
storage::neurons::NeuronSections,
Expand Down Expand Up @@ -131,9 +132,14 @@ impl NeuronStore {
let mut total_deciding_voting_power: u128 = 0;
let mut total_potential_voting_power: u128 = 0;

let default_min_dissolve_delay = if is_mission_70_voting_rewards_enabled() {
14 * ic_nervous_system_common::ONE_DAY_SECONDS
} else {
VotingPowerEconomics::DEFAULT_NEURON_MINIMUM_DISSOLVE_DELAY_TO_VOTE_SECONDS
};
Comment on lines +135 to +139
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, this code is repeated. Oh well. Temporary.

let min_dissolve_delay_seconds = voting_power_economics
.neuron_minimum_dissolve_delay_to_vote_seconds
.unwrap_or(VotingPowerEconomics::DEFAULT_NEURON_MINIMUM_DISSOLVE_DELAY_TO_VOTE_SECONDS);
.unwrap_or(default_min_dissolve_delay);

let mut process_neuron = |neuron: &Neuron| {
if neuron.is_inactive(now_seconds)
Expand Down
Loading