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

chore(sns): Obsolete airdrop neurons from initial SNS configuration #4137

Merged
merged 8 commits into from
Mar 4, 2025
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use ic_nervous_system_common::MAX_NEURONS_FOR_DIRECT_PARTICIPANTS;
use ic_nns_governance::governance::MAX_NEURONS_FUND_PARTICIPANTS;
use ic_sns_governance::pb::v1::NervousSystemParameters;
use ic_sns_init::{
distributions::{MAX_AIRDROP_DISTRIBUTION_COUNT, MAX_DEVELOPER_DISTRIBUTION_COUNT},
MAX_SNS_NEURONS_PER_BASKET,
};
use ic_sns_init::{distributions::MAX_DEVELOPER_DISTRIBUTION_COUNT, MAX_SNS_NEURONS_PER_BASKET};

// Test that the total number of SNS neurons created by an SNS swap is within the ceiling expected
// by SNS Governance (`MAX_NUMBER_OF_NEURONS_CEILING`). Concretely, the test compares this constant
Expand Down Expand Up @@ -46,19 +43,13 @@ fn test_max_number_of_sns_neurons_adds_up() {
NervousSystemParameters::MAX_NUMBER_OF_NEURONS_CEILING
>= MAX_SNS_NEURONS_PER_BASKET * MAX_NEURONS_FUND_PARTICIPANTS
+ MAX_NEURONS_FOR_DIRECT_PARTICIPANTS
+ MAX_DEVELOPER_DISTRIBUTION_COUNT as u64
+ MAX_AIRDROP_DISTRIBUTION_COUNT as u64,
+ MAX_DEVELOPER_DISTRIBUTION_COUNT as u64,
"MAX_NUMBER_OF_NEURONS_CEILING ({}) must be >= \
MAX_SNS_NEURONS_PER_BASKET ({}) * MAX_NEURONS_FUND_PARTICIPANTS ({}) \
+ MAX_NEURONS_FOR_DIRECT_PARTICIPANTS ({}) \
+ MAX_DEVELOPER_DISTRIBUTION_COUNT ({}) \
+ MAX_AIRDROP_DISTRIBUTION_COUNT ({}).\n{}",
NervousSystemParameters::MAX_NUMBER_OF_NEURONS_CEILING,
MAX_SNS_NEURONS_PER_BASKET,
MAX_NEURONS_FUND_PARTICIPANTS,
MAX_NEURONS_FOR_DIRECT_PARTICIPANTS,
MAX_DEVELOPER_DISTRIBUTION_COUNT,
MAX_AIRDROP_DISTRIBUTION_COUNT,
RECOMMENDATION
MAX_SNS_NEURONS_PER_BASKET ({MAX_SNS_NEURONS_PER_BASKET}) * \
MAX_NEURONS_FUND_PARTICIPANTS ({MAX_NEURONS_FUND_PARTICIPANTS}) \
+ MAX_NEURONS_FOR_DIRECT_PARTICIPANTS ({MAX_NEURONS_FOR_DIRECT_PARTICIPANTS}) \
+ MAX_DEVELOPER_DISTRIBUTION_COUNT ({MAX_DEVELOPER_DISTRIBUTION_COUNT}).\n\
{RECOMMENDATION}",
NervousSystemParameters::MAX_NUMBER_OF_NEURONS_CEILING
);
}
8 changes: 2 additions & 6 deletions rs/nns/governance/src/governance/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,9 +452,7 @@ mod convert_from_create_service_nervous_system_to_sns_init_payload_tests {
total_e8s: swap_total_e8s,
initial_swap_amount_e8s: swap_total_e8s,
},),
airdrop_distribution: Some(sns_init_pb::AirdropDistribution {
airdrop_neurons: vec![],
},),
airdrop_distribution: None,
},
),
);
Expand Down Expand Up @@ -796,9 +794,7 @@ mod convert_create_service_nervous_system_proposal_to_sns_init_payload_tests_wit
total_e8s: swap_total_e8s,
initial_swap_amount_e8s: swap_total_e8s,
},),
airdrop_distribution: Some(sns_init_pb::AirdropDistribution {
airdrop_neurons: vec![],
},),
airdrop_distribution: None,
},
),
);
Expand Down
4 changes: 3 additions & 1 deletion rs/nns/sns-wasm/canister/sns-wasm.did
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ type DeveloperDistribution = record {
type FractionalDeveloperVotingPower = record {
treasury_distribution : opt TreasuryDistribution;
developer_distribution : opt DeveloperDistribution;
airdrop_distribution : opt AirdropDistribution;
swap_distribution : opt SwapDistribution;

// Obsolete fields.
airdrop_distribution : opt AirdropDistribution;
};

type GetAllowedPrincipalsResponse = record {
Expand Down
116 changes: 51 additions & 65 deletions rs/nns/sns-wasm/tests/upgrade_sns_instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use ic_sns_governance::{
types::E8S_PER_TOKEN,
};
use ic_sns_init::pb::v1::{
sns_init_payload::InitialTokenDistribution, AirdropDistribution, DeveloperDistribution,
sns_init_payload::InitialTokenDistribution, DeveloperDistribution,
FractionalDeveloperVotingPower, NeuronDistribution, SnsInitPayload, SwapDistribution,
TreasuryDistribution,
};
Expand Down Expand Up @@ -102,7 +102,13 @@ fn test_governance_restarts_root_if_root_cannot_stop_during_upgrade() {
initial_token_distribution: Some(InitialTokenDistribution::FractionalDeveloperVotingPower(
FractionalDeveloperVotingPower {
developer_distribution: Some(DeveloperDistribution {
developer_neurons: Default::default(),
developer_neurons: vec![NeuronDistribution {
controller: Some(user),
stake_e8s: 10_000_000_000,
memo: 0,
dissolve_delay_seconds: 15780000, // 6 months
vesting_period_seconds: None,
}],
}),
treasury_distribution: Some(TreasuryDistribution {
total_e8s: 500_000_000,
Expand All @@ -111,23 +117,15 @@ fn test_governance_restarts_root_if_root_cannot_stop_during_upgrade() {
total_e8s: 10_000_000_000,
initial_swap_amount_e8s: 10_000_000_000,
}),
airdrop_distribution: Some(AirdropDistribution {
airdrop_neurons: vec![NeuronDistribution {
controller: Some(user),
stake_e8s: 2_000_000_000_000,
memo: 0,
dissolve_delay_seconds: 15780000, // 6 months
vesting_period_seconds: None,
}],
}),
airdrop_distribution: None,
},
)),
..SnsInitPayload::with_valid_values_for_testing_post_execution()
};

// Will be used to make proposals and such. Fortunately, this guy has lots
// of money -> he'll be able to push proposals though.
let airdrop_sns_neuron_id = sns_governance_pb::NeuronId {
let developer_sns_neuron_id = sns_governance_pb::NeuronId {
id: compute_neuron_staking_subaccount(user, /* memo */ 0)
.0
.to_vec(),
Expand Down Expand Up @@ -167,7 +165,7 @@ fn test_governance_restarts_root_if_root_cannot_stop_during_upgrade() {
&machine,
governance,
user,
airdrop_sns_neuron_id,
developer_sns_neuron_id,
Proposal {
title: "Upgrade Canister.".into(),
action: Some(Action::UpgradeSnsToNextVersion(UpgradeSnsToNextVersion {})),
Expand Down Expand Up @@ -242,24 +240,22 @@ fn run_upgrade_test(canister_type: SnsCanisterType) {
initial_token_distribution: Some(InitialTokenDistribution::FractionalDeveloperVotingPower(
FractionalDeveloperVotingPower {
developer_distribution: Some(DeveloperDistribution {
developer_neurons: Default::default(),
developer_neurons: vec![NeuronDistribution {
controller: Some(user),
stake_e8s: 100_000_000_000,
memo: 0,
dissolve_delay_seconds: 15780000, // 6 months
vesting_period_seconds: None,
}],
}),
treasury_distribution: Some(TreasuryDistribution {
total_e8s: 500_000_000,
}),
swap_distribution: Some(SwapDistribution {
total_e8s: 10_000_000_000,
total_e8s: 100_000_000_000,
initial_swap_amount_e8s: 10_000_000_000,
}),
airdrop_distribution: Some(AirdropDistribution {
airdrop_neurons: vec![NeuronDistribution {
controller: Some(user),
stake_e8s: 2_000_000_000_000,
memo: 0,
dissolve_delay_seconds: 15780000, // 6 months
vesting_period_seconds: None,
}],
}),
airdrop_distribution: None,
},
)),
..SnsInitPayload::with_valid_values_for_testing_post_execution()
Expand Down Expand Up @@ -485,18 +481,26 @@ fn upgrade_archive_sns_canister_via_sns_wasms() {

let wasm_map = sns_wasm::add_real_wasms_to_sns_wasms(&machine);

// To get an SNS neuron, we airdrop our new tokens to this user.
// This user will act as the fallback controller and the big developer neuron controller.
let user = PrincipalId::new_user_test_id(0);

let airdrop_neuron = |number| NeuronDistribution {
let mut developer_neurons = vec![NeuronDistribution {
controller: Some(user),
stake_e8s: 80_000_000_000,
memo: 0,
dissolve_delay_seconds: 15780000, // 6 months
vesting_period_seconds: None,
}];

// We make these to create some extra transactions so an archive will spawn.
let make_neuron_distribution = |number| NeuronDistribution {
controller: Some(PrincipalId::new_user_test_id(number)),
stake_e8s: 100_000_000,
memo: 0,
dissolve_delay_seconds: 15780000, // 6 months
vesting_period_seconds: None,
};
// We make these to create some extra transactions so an archive will spawn.
let airdrop_neurons: Vec<NeuronDistribution> = (1..20_u64).map(airdrop_neuron).collect();
developer_neurons.extend((1..20_u64).map(make_neuron_distribution));

let payload = SnsInitPayload {
transaction_fee_e8s: Some(DEFAULT_TRANSFER_FEE.get_e8s()),
Expand All @@ -507,28 +511,15 @@ fn upgrade_archive_sns_canister_via_sns_wasms() {
fallback_controller_principal_ids: vec![user.to_string()],
initial_token_distribution: Some(InitialTokenDistribution::FractionalDeveloperVotingPower(
FractionalDeveloperVotingPower {
developer_distribution: Some(DeveloperDistribution {
developer_neurons: Default::default(),
}),
developer_distribution: Some(DeveloperDistribution { developer_neurons }),
treasury_distribution: Some(TreasuryDistribution {
total_e8s: 500_000_000,
}),
swap_distribution: Some(SwapDistribution {
total_e8s: 10_000_000_000,
total_e8s: 100_000_000_000,
initial_swap_amount_e8s: 10_000_000_000,
}),
airdrop_distribution: Some(AirdropDistribution {
airdrop_neurons: vec![NeuronDistribution {
controller: Some(user),
stake_e8s: 2_000_000_000_000,
memo: 0,
dissolve_delay_seconds: 15780000, // 6 months
vesting_period_seconds: None,
}]
.into_iter()
.chain(airdrop_neurons)
.collect(),
}),
airdrop_distribution: None,
},
)),
..SnsInitPayload::with_valid_values_for_testing_post_execution()
Expand Down Expand Up @@ -739,18 +730,26 @@ fn test_out_of_sync_version_still_allows_upgrade_to_succeed() {
}
let wasm_map = sns_wasm::add_freshly_built_sns_wasms(&machine, filter_wasm);

// To get an SNS neuron, we airdrop our new tokens to this user.
// This user will act as the fallback controller and the big developer neuron controller.
let user = PrincipalId::new_user_test_id(0);

let airdrop_neuron = |number| NeuronDistribution {
let mut developer_neurons = vec![NeuronDistribution {
controller: Some(user),
stake_e8s: 80_000_000_000,
memo: 0,
dissolve_delay_seconds: 15780000, // 6 months
vesting_period_seconds: None,
}];

// We make these to create some extra transactions so an archive will spawn.
let make_neuron_distribution = |number| NeuronDistribution {
controller: Some(PrincipalId::new_user_test_id(number)),
stake_e8s: 100_000_000,
memo: 0,
dissolve_delay_seconds: 15780000, // 6 months
vesting_period_seconds: None,
};
// We make these to create some extra transactions so an archive will spawn.
let airdrop_neurons: Vec<NeuronDistribution> = (1..20_u64).map(airdrop_neuron).collect();
developer_neurons.extend((1..20_u64).map(make_neuron_distribution));

let payload = SnsInitPayload {
transaction_fee_e8s: Some(DEFAULT_TRANSFER_FEE.get_e8s()),
Expand All @@ -761,28 +760,15 @@ fn test_out_of_sync_version_still_allows_upgrade_to_succeed() {
fallback_controller_principal_ids: vec![user.to_string()],
initial_token_distribution: Some(InitialTokenDistribution::FractionalDeveloperVotingPower(
FractionalDeveloperVotingPower {
developer_distribution: Some(DeveloperDistribution {
developer_neurons: Default::default(),
}),
developer_distribution: Some(DeveloperDistribution { developer_neurons }),
treasury_distribution: Some(TreasuryDistribution {
total_e8s: 500_000_000,
}),
swap_distribution: Some(SwapDistribution {
total_e8s: 10_000_000_000,
initial_swap_amount_e8s: 10_000_000_000,
}),
airdrop_distribution: Some(AirdropDistribution {
airdrop_neurons: vec![NeuronDistribution {
controller: Some(user),
stake_e8s: 2_000_000_000_000,
memo: 0,
dissolve_delay_seconds: 15780000, // 6 months
vesting_period_seconds: None,
}]
.into_iter()
.chain(airdrop_neurons)
.collect(),
total_e8s: 100_000_000_000,
initial_swap_amount_e8s: 100_000_000_000,
}),
airdrop_distribution: None,
},
)),
..SnsInitPayload::with_valid_values_for_testing_post_execution()
Expand Down
2 changes: 2 additions & 0 deletions rs/nns/sns-wasm/unreleased_changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ on the process that this file is part of, see

## Removed

* Remove (previously deprecated) airdrop neurons from initial SNS configuration. `SnsInitPayload.initial_token_distribution` must not specify any neurons in `airdrop_distribution`.

## Fixed

## Security
1 change: 1 addition & 0 deletions rs/sns/init/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ DEV_DEPENDENCIES = [
"//rs/sns/init/protobuf_generator:lib",
"//rs/test_utilities/compare_dirs",
"@crate_index//:num-traits",
"@crate_index//:pretty_assertions",
"@crate_index//:tempfile",
]

Expand Down
1 change: 1 addition & 0 deletions rs/sns/init/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ ic-nervous-system-common-test-keys = { path = "../../nervous_system/common/test_
ic-sns-init-protobuf-generator = { path = "protobuf_generator" }
ic-test-utilities-compare-dirs = { path = "../../test_utilities/compare_dirs" }
num-traits = { workspace = true }
pretty_assertions = { workspace = true }
tempfile = { workspace = true }

[features]
Expand Down
10 changes: 3 additions & 7 deletions rs/sns/init/proto/ic_sns_init/pb/v1/sns_init.proto
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ message SnsInitPayload {

// The FractionalDeveloperVotingPower token distribution strategy configures
// how tokens and neurons are distributed via four "buckets": developers,
// treasury, swap, and airdrops. This strategy will distribute all developer tokens
// treasury, and swap. This strategy will distribute all developer tokens
// at genesis in restricted neurons with an additional voting power
// multiplier applied. This voting power multiplier is calculated as
// `swap_distribution.initial_swap_amount_e8s / swap_distribution.total_e8s`.
Expand All @@ -239,7 +239,6 @@ message SnsInitPayload {
// it to be a valid distribution:
// - developer_distribution.developer_neurons.stake_e8s.sum <= u64:MAX
// - developer_neurons.developer_neurons.stake_e8s.sum <= swap_distribution.total_e8s
// - airdrop_distribution.airdrop_neurons.stake_e8s.sum <= u64:MAX
// - swap_distribution.initial_swap_amount_e8s > 0
// - swap_distribution.initial_swap_amount_e8s <= swap_distribution.total_e8s
// - swap_distribution.total_e8s >= developer_distribution.developer_neurons.stake_e8s.sum
Expand All @@ -253,7 +252,7 @@ message FractionalDeveloperVotingPower {
// The swap bucket.
SwapDistribution swap_distribution = 3;

// The airdrop bucket.
// OBSOLETE.
AirdropDistribution airdrop_distribution = 4;
}

Expand Down Expand Up @@ -287,11 +286,8 @@ message SwapDistribution {
uint64 initial_swap_amount_e8s = 2;
}

// The distributions airdropped at SNS genesis.
// OBSOLETE.
message AirdropDistribution {
// List of `NeuronDistribution` that specify a Neuron controller and Neuron stake in e8s
// (10E-8 of a token). For each entry in the airdrop_neurons list, a neuron will be
// created with NO voting multiplier applied and will start in PreInitializationSwap mode.
repeated NeuronDistribution airdrop_neurons = 1;
}

Expand Down
11 changes: 5 additions & 6 deletions rs/sns/init/src/create_service_nervous_system.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::pb::v1::{
sns_init_payload, AirdropDistribution, DappCanisters, DeveloperDistribution,
FractionalDeveloperVotingPower, NeuronDistribution, SnsInitPayload, SwapDistribution,
TreasuryDistribution,
sns_init_payload, DappCanisters, DeveloperDistribution, FractionalDeveloperVotingPower,
NeuronDistribution, SnsInitPayload, SwapDistribution, TreasuryDistribution,
};
use ic_nns_governance_api::pb::v1::{create_service_nervous_system, CreateServiceNervousSystem};

Expand Down Expand Up @@ -321,8 +320,6 @@ impl TryFrom<create_service_nervous_system::InitialTokenDistribution>
}
};

let airdrop_distribution = Some(AirdropDistribution::default());

if !defects.is_empty() {
return Err(format!(
"Failed to convert to InitialTokenDistribution for the following reasons:\n{}",
Expand All @@ -335,7 +332,9 @@ impl TryFrom<create_service_nervous_system::InitialTokenDistribution>
developer_distribution,
treasury_distribution,
swap_distribution,
airdrop_distribution,

// Obsolete fields.
airdrop_distribution: None,
},
))
}
Expand Down
Loading