Skip to content

Commit

Permalink
Make into_api sort recent_ballots.
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-wong-dfinity-org committed Jan 30, 2025
1 parent 415041d commit fa9565d
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 2 deletions.
3 changes: 2 additions & 1 deletion rs/nns/governance/src/neuron/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1358,6 +1358,7 @@ impl Neuron {
let deciding_voting_power =
Some(self.deciding_voting_power(voting_power_economics, now_seconds));
let potential_voting_power = Some(self.potential_voting_power(now_seconds));
let recent_ballots = self.sorted_recent_ballots();

let Neuron {
id,
Expand All @@ -1370,7 +1371,7 @@ impl Neuron {
created_timestamp_seconds,
spawn_at_timestamp_seconds,
followees,
recent_ballots,
recent_ballots: _,
kyc_verified,
transfer,
maturity_e8s_equivalent,
Expand Down
118 changes: 117 additions & 1 deletion rs/nns/governance/src/neuron/types/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,130 @@ use crate::{
temporarily_enable_private_neuron_enforcement, temporarily_enable_voting_power_adjustment,
};
use ic_cdk::println;

use ic_nervous_system_common::{E8, ONE_MONTH_SECONDS, ONE_YEAR_SECONDS};
use icp_ledger::Subaccount;
use maplit::hashmap;
use pretty_assertions::assert_eq;

const NOW: u64 = 123_456_789;

const TWELVE_MONTHS_SECONDS: u64 = 30 * 12 * 24 * 60 * 60;

/// Our main goal here is to make sure that recent_ballots is populated
/// correctly.
#[test]
fn test_neuron_into_api() {
// Step 1: Prepare "the world". In this case, that just consists of
// constructing a native Neuron.

let some_timestamp_seconds = 1738239721;

let dissolve_state_and_age = DissolveStateAndAge::NotDissolving {
dissolve_delay_seconds: 100,
aging_since_timestamp_seconds: some_timestamp_seconds + 30,
};

let mut original_neuron = NeuronBuilder::new(
NeuronId { id: 7 },
Subaccount::try_from(vec![8_u8; 32].as_slice()).unwrap(),
PrincipalId::new_user_test_id(9),
dissolve_state_and_age,
some_timestamp_seconds + 3, // created_timestamp_seconds
)
.build();

// Add ballots.
for i in 0..10 {
let proposal_id = Some(ProposalId { id: 123_000 + i });

original_neuron.recent_ballots.push(pb::BallotInfo {
proposal_id,
vote: Vote::No as i32,
});
};
original_neuron.recent_ballots_next_entry_index = Some(3);

// Step 2: run code under test.
let api_neuron = original_neuron.clone().into_api(some_timestamp_seconds + 99, &VotingPowerEconomics::DEFAULT);

// Step 3: Inspect result(s).

// Survives round trip.
assert_eq!(
Neuron {
// This is checked separately.
recent_ballots: vec![],
..Neuron::try_from(api_neuron.clone()).unwrap()
},
Neuron {
recent_ballots: vec![],
recent_ballots_next_entry_index: None,
visibility: Some(pb::Visibility::Private),
..original_neuron.clone()
}
);

// Verify most fields, or at least, the interesting ones.
let potential_voting_power = Some(original_neuron.potential_voting_power(some_timestamp_seconds + 99));
let deciding_voting_power = Some(original_neuron.deciding_voting_power(&VotingPowerEconomics::DEFAULT, some_timestamp_seconds + 99));
assert_eq!(
api::Neuron {
recent_ballots: vec![],
..api_neuron.clone()
},
api::Neuron {
// Fields with "interesting" values.
id: Some(NeuronId { id: 7 }),
account: vec![8_u8; 32],
controller: Some(PrincipalId::new_user_test_id(9)),
dissolve_state: Some(api::neuron::DissolveState::DissolveDelaySeconds(100)),
aging_since_timestamp_seconds: some_timestamp_seconds + 30,
created_timestamp_seconds: some_timestamp_seconds + 3,
visibility: Some(Visibility::Private as i32),
voting_power_refreshed_timestamp_seconds: Some(some_timestamp_seconds + 3),

// Other fields have default value.
hot_keys: vec![],
cached_neuron_stake_e8s: 0,
neuron_fees_e8s: 0,
spawn_at_timestamp_seconds: None,
followees: hashmap!{},
recent_ballots: vec![],
kyc_verified: false,
transfer: None,
maturity_e8s_equivalent: 0,
staked_maturity_e8s_equivalent: None,
auto_stake_maturity: None,
not_for_profit: false,
joined_community_fund_timestamp_seconds: None,
known_neuron_data: None,
neuron_type: None,
potential_voting_power,
deciding_voting_power,
},
);

// In particular, recent_ballots_next_entry_index is used (indirectly) during conversion.
let expected_proposal_ids = vec![
123_002, 123_001, 123_000, 123_009, 123_008, 123_007, 123_006, 123_005, 123_004, 123_003,
];
assert_eq!(expected_proposal_ids.len(), 10);
assert_eq!(
api_neuron.recent_ballots,
expected_proposal_ids
.into_iter()
.map(|id| {
let proposal_id = Some(ProposalId { id });

api::BallotInfo {
proposal_id,
vote: Vote::No as i32,
}
})
.collect::<Vec<_>>(),
);
}

#[test]
fn test_dissolve_state_and_age_conversion() {
let test_cases = vec![
Expand Down

0 comments on commit fa9565d

Please sign in to comment.