Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(nns): move cast_vote_and_cascade_following tests to voting.rs #2930

Merged
merged 1 commit into from
Dec 2, 2024
Merged
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
238 changes: 0 additions & 238 deletions rs/nns/governance/src/governance/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1134,244 +1134,6 @@ mod neuron_archiving_tests {
} // end proptest
}

mod cast_vote_and_cascade_follow {
use crate::{
governance::{Governance, MIN_DISSOLVE_DELAY_FOR_VOTE_ELIGIBILITY_SECONDS},
neuron::{DissolveStateAndAge, Neuron, NeuronBuilder},
pb::v1::{neuron::Followees, Ballot, ProposalData, Topic, Vote},
test_utils::{MockEnvironment, StubCMC, StubIcpLedger},
};
use futures::FutureExt;
use ic_base_types::PrincipalId;
use ic_nns_common::pb::v1::{NeuronId, ProposalId};
use icp_ledger::Subaccount;
use maplit::{btreemap, hashmap};
use std::collections::{BTreeMap, HashMap};

fn make_ballot(voting_power: u64, vote: Vote) -> Ballot {
Ballot {
voting_power,
vote: vote as i32,
}
}

fn make_test_neuron_with_followees(
id: u64,
topic: Topic,
followees: Vec<u64>,
aging_since_timestamp_seconds: u64,
) -> Neuron {
NeuronBuilder::new(
NeuronId { id },
Subaccount::try_from(&[0u8; 32] as &[u8]).unwrap(),
PrincipalId::new_user_test_id(1),
DissolveStateAndAge::NotDissolving {
dissolve_delay_seconds: MIN_DISSOLVE_DELAY_FOR_VOTE_ELIGIBILITY_SECONDS,
aging_since_timestamp_seconds,
},
123_456_789,
)
.with_followees(hashmap! {
topic as i32 => Followees {
followees: followees.into_iter().map(|id| NeuronId { id }).collect()
}
})
.build()
}

#[test]
fn test_cast_vote_and_cascade_doesnt_cascade_neuron_management() {
let now = 1000;
let topic = Topic::NeuronManagement;

let make_neuron = |id: u64, followees: Vec<u64>| {
make_test_neuron_with_followees(id, topic, followees, now)
};

let add_neuron_with_ballot = |neuron_map: &mut BTreeMap<u64, Neuron>,
ballots: &mut HashMap<u64, Ballot>,
id: u64,
followees: Vec<u64>,
vote: Vote| {
let neuron = make_neuron(id, followees);
let deciding_voting_power = neuron.deciding_voting_power(now);
neuron_map.insert(id, neuron);
ballots.insert(id, make_ballot(deciding_voting_power, vote));
};

let add_neuron_without_ballot =
|neuron_map: &mut BTreeMap<u64, Neuron>, id: u64, followees: Vec<u64>| {
let neuron = make_neuron(id, followees);
neuron_map.insert(id, neuron);
};

let mut heap_neurons = BTreeMap::new();
let mut ballots = HashMap::new();
for id in 1..=5 {
// Each neuron follows all neurons with a lower id
let followees = (1..id).collect();

add_neuron_with_ballot(
&mut heap_neurons,
&mut ballots,
id,
followees,
Vote::Unspecified,
);
}
// Add another neuron that follows both a neuron with a ballot and without a ballot
add_neuron_with_ballot(
&mut heap_neurons,
&mut ballots,
6,
vec![1, 7],
Vote::Unspecified,
);

// Add a neuron without a ballot for neuron 6 to follow.
add_neuron_without_ballot(&mut heap_neurons, 7, vec![1]);

let governance_proto = crate::pb::v1::Governance {
neurons: heap_neurons
.into_iter()
.map(|(id, neuron)| (id, neuron.into_proto(now)))
.collect(),
proposals: btreemap! {
1 => ProposalData {
id: Some(ProposalId {id: 1}),
ballots,
..Default::default()
}
},
..Default::default()
};
let mut governance = Governance::new(
governance_proto,
Box::new(MockEnvironment::new(Default::default(), 0)),
Box::new(StubIcpLedger {}),
Box::new(StubCMC {}),
);

governance
.cast_vote_and_cascade_follow(
ProposalId { id: 1 },
NeuronId { id: 1 },
Vote::Yes,
topic,
)
.now_or_never()
.unwrap();

let deciding_voting_power = |neuron_id| {
governance
.neuron_store
.with_neuron(&neuron_id, |n| n.deciding_voting_power(now))
.unwrap()
};
assert_eq!(
governance.heap_data.proposals.get(&1).unwrap().ballots,
hashmap! {
1 => make_ballot(deciding_voting_power(NeuronId { id: 1}), Vote::Yes),
2 => make_ballot(deciding_voting_power(NeuronId { id: 2}), Vote::Unspecified),
3 => make_ballot(deciding_voting_power(NeuronId { id: 3}), Vote::Unspecified),
4 => make_ballot(deciding_voting_power(NeuronId { id: 4}), Vote::Unspecified),
5 => make_ballot(deciding_voting_power(NeuronId { id: 5}), Vote::Unspecified),
6 => make_ballot(deciding_voting_power(NeuronId { id: 6}), Vote::Unspecified),
}
);
}

#[test]
fn test_cast_vote_and_cascade_works() {
let now = 1000;
let topic = Topic::NetworkCanisterManagement;

let make_neuron = |id: u64, followees: Vec<u64>| {
make_test_neuron_with_followees(id, topic, followees, now)
};

let add_neuron_with_ballot = |neuron_map: &mut BTreeMap<u64, Neuron>,
ballots: &mut HashMap<u64, Ballot>,
id: u64,
followees: Vec<u64>,
vote: Vote| {
let neuron = make_neuron(id, followees);
let deciding_voting_power = neuron.deciding_voting_power(now);
neuron_map.insert(id, neuron);
ballots.insert(id, make_ballot(deciding_voting_power, vote));
};

let add_neuron_without_ballot =
|neuron_map: &mut BTreeMap<u64, Neuron>, id: u64, followees: Vec<u64>| {
let neuron = make_neuron(id, followees);
neuron_map.insert(id, neuron);
};

let mut neurons = BTreeMap::new();
let mut ballots = HashMap::new();
for id in 1..=5 {
// Each neuron follows all neurons with a lower id
let followees = (1..id).collect();

add_neuron_with_ballot(&mut neurons, &mut ballots, id, followees, Vote::Unspecified);
}
// Add another neuron that follows both a neuron with a ballot and without a ballot
add_neuron_with_ballot(&mut neurons, &mut ballots, 6, vec![1, 7], Vote::Unspecified);

// Add a neuron without a ballot for neuron 6 to follow.
add_neuron_without_ballot(&mut neurons, 7, vec![1]);

let governance_proto = crate::pb::v1::Governance {
neurons: neurons
.into_iter()
.map(|(id, neuron)| (id, neuron.into_proto(now)))
.collect(),
proposals: btreemap! {
1 => ProposalData {
id: Some(ProposalId {id: 1}),
ballots,
..Default::default()
}
},
..Default::default()
};
let mut governance = Governance::new(
governance_proto,
Box::new(MockEnvironment::new(Default::default(), 0)),
Box::new(StubIcpLedger {}),
Box::new(StubCMC {}),
);

governance
.cast_vote_and_cascade_follow(
ProposalId { id: 1 },
NeuronId { id: 1 },
Vote::Yes,
topic,
)
.now_or_never()
.unwrap();

let deciding_voting_power = |neuron_id| {
governance
.neuron_store
.with_neuron(&neuron_id, |n| n.deciding_voting_power(now))
.unwrap()
};
assert_eq!(
governance.heap_data.proposals.get(&1).unwrap().ballots,
hashmap! {
1 => make_ballot(deciding_voting_power(NeuronId { id: 1 }), Vote::Yes),
2 => make_ballot(deciding_voting_power(NeuronId { id: 2 }), Vote::Yes),
3 => make_ballot(deciding_voting_power(NeuronId { id: 3 }), Vote::Yes),
4 => make_ballot(deciding_voting_power(NeuronId { id: 4 }), Vote::Yes),
5 => make_ballot(deciding_voting_power(NeuronId { id: 5 }), Vote::Yes),
6 => make_ballot(deciding_voting_power(NeuronId { id: 6 }), Vote::Unspecified),
}
);
}
}

#[test]
fn test_pre_and_post_upgrade_first_time() {
let neuron1 = NeuronProto {
Expand Down
Loading
Loading