Skip to content

Commit 2008d47

Browse files
feat(nns): Validate manage network economics. (#3859)
# Reference(s) Closes [NNS1-3498]. [NNS1-3498]: https://dfinity.atlassian.net/browse/NNS1-3498
1 parent 8a3737f commit 2008d47

File tree

6 files changed

+799
-32
lines changed

6 files changed

+799
-32
lines changed

rs/nns/governance/src/governance.rs

Lines changed: 78 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use crate::{
1111
reassemble_governance_proto, split_governance_proto, HeapGovernanceData, XdrConversionRate,
1212
},
1313
migrations::maybe_run_migrations,
14-
network_economics::InheritFrom,
1514
neuron::{DissolveStateAndAge, Neuron, NeuronBuilder, Visibility},
1615
neuron_data_validation::{NeuronDataValidationSummary, NeuronDataValidator},
1716
neuron_store::{
@@ -4356,8 +4355,7 @@ impl Governance {
43564355
}
43574356
}
43584357
Action::ManageNetworkEconomics(network_economics) => {
4359-
self.perform_manage_network_economics(network_economics);
4360-
self.set_proposal_execution_status(pid, Ok(()));
4358+
self.perform_manage_network_economics(pid, network_economics);
43614359
}
43624360
// A motion is not executed, just recorded for posterity.
43634361
Action::Motion(_) => {
@@ -4522,20 +4520,40 @@ impl Governance {
45224520
);
45234521
}
45244522

4525-
fn perform_manage_network_economics(&mut self, new_network_economics: NetworkEconomics) {
4526-
let Some(original_network_economics) = &self.heap_data.economics else {
4527-
// This wouldn't happen in production, but if it does, we try to do
4528-
// the best we can, because doing nothing seems more catastrophic.
4529-
println!(
4530-
"{}ERROR: NetworkEconomics was not set. Setting to proposed NetworkEconomics:\n{:#?}",
4531-
LOG_PREFIX, new_network_economics,
4532-
);
4533-
self.heap_data.economics = Some(new_network_economics);
4534-
return;
4535-
};
4523+
fn perform_manage_network_economics(
4524+
&mut self,
4525+
proposal_id: u64,
4526+
proposed_network_economics: NetworkEconomics,
4527+
) {
4528+
let result = self.perform_manage_network_economics_impl(proposed_network_economics);
4529+
self.set_proposal_execution_status(proposal_id, result);
4530+
}
4531+
4532+
/// Only call this from perform_manage_network_economics.
4533+
fn perform_manage_network_economics_impl(
4534+
&mut self,
4535+
proposed_network_economics: NetworkEconomics,
4536+
) -> Result<(), GovernanceError> {
4537+
let new_network_economics = self
4538+
.economics()
4539+
.apply_changes_and_validate(&proposed_network_economics)
4540+
.map_err(|defects| {
4541+
GovernanceError::new_with_message(
4542+
ErrorType::InvalidProposal,
4543+
format!(
4544+
"The resulting NetworkEconomics is invalid for the following reason(s):\
4545+
\n - {}",
4546+
defects.join("\n - "),
4547+
),
4548+
)
4549+
})?;
45364550

4537-
self.heap_data.economics =
4538-
Some(new_network_economics.inherit_from(original_network_economics));
4551+
println!(
4552+
"{}INFO: Committing new NetworkEconomics:\n{:#?}",
4553+
LOG_PREFIX, new_network_economics,
4554+
);
4555+
self.heap_data.economics = Some(new_network_economics);
4556+
Ok(())
45394557
}
45404558

45414559
async fn perform_install_code(&mut self, proposal_id: u64, install_code: InstallCode) {
@@ -4883,6 +4901,45 @@ impl Governance {
48834901
Ok(())
48844902
}
48854903

4904+
/// This verifies the following:
4905+
///
4906+
/// 1. When the changes are applied, the resulting NetworkEconomics is
4907+
/// valid. See NetworkEconomics::validate.
4908+
///
4909+
/// Since self.heap_data.economics can be different when a proposal is
4910+
/// executed (compared to when it is created), this should be performed both
4911+
/// at proposal creation time AND execution time.
4912+
///
4913+
/// Note that it is not considered "invalid" when the "modified" result is
4914+
/// the same as the original (i.e. setting F to V even though the current
4915+
/// value of F is ALREADY V). This is because such a proposal is not
4916+
/// actually harmful to the system; just maybe confusing to users.
4917+
fn validate_manage_network_economics(
4918+
&self,
4919+
// (Note that this is the value associated with ManageNetworkEconomics,
4920+
// not the resulting NetworkEconomics.)
4921+
proposed_network_economics: &NetworkEconomics,
4922+
) -> Result<(), GovernanceError> {
4923+
// It maybe does not make sense to be able to set transaction_fee_e8s
4924+
// via proposal. What we probably want instead is to fetch this value
4925+
// from ledger.
4926+
4927+
self.economics()
4928+
.apply_changes_and_validate(proposed_network_economics)
4929+
.map_err(|defects| {
4930+
let message = format!(
4931+
"The resulting settings would not be valid for the \
4932+
following reason(s):\n\
4933+
- {}",
4934+
defects.join("\n - "),
4935+
);
4936+
4937+
GovernanceError::new_with_message(ErrorType::InvalidProposal, message)
4938+
})?;
4939+
4940+
Ok(())
4941+
}
4942+
48864943
pub(crate) fn economics(&self) -> &NetworkEconomics {
48874944
self.heap_data
48884945
.economics
@@ -4960,8 +5017,11 @@ impl Governance {
49605017
Action::ManageNeuron(manage_neuron) => {
49615018
self.validate_manage_neuron_proposal(manage_neuron)
49625019
}
4963-
Action::ManageNetworkEconomics(_)
4964-
| Action::ApproveGenesisKyc(_)
5020+
Action::ManageNetworkEconomics(network_economics) => {
5021+
self.validate_manage_network_economics(network_economics)
5022+
}
5023+
5024+
Action::ApproveGenesisKyc(_)
49655025
| Action::AddOrRemoveNodeProvider(_)
49665026
| Action::RewardNodeProvider(_)
49675027
| Action::RewardNodeProviders(_)

rs/nns/governance/src/governance_proto_builder.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::pb::v1::{
22
Governance as GovernancePb, NetworkEconomics as NetworkEconomicsPb, Neuron as NeuronPb,
3-
ProposalData as ProposalPb, RewardEvent as RewardEventPb,
3+
NeuronsFundEconomics, ProposalData as ProposalPb, RewardEvent as RewardEventPb,
4+
VotingPowerEconomics,
45
};
56

67
pub struct GovernanceProtoBuilder {
@@ -16,13 +17,22 @@ impl Default for GovernanceProtoBuilder {
1617
impl GovernanceProtoBuilder {
1718
/// Minimaly valid Governance proto.
1819
pub fn new() -> Self {
19-
let governance_proto = GovernancePb {
20+
let mut governance_proto = GovernancePb {
2021
wait_for_quiet_threshold_seconds: 1,
2122
short_voting_period_seconds: 30,
2223
neuron_management_voting_period_seconds: Some(30),
2324
economics: Some(NetworkEconomicsPb::default()),
2425
..Default::default()
2526
};
27+
28+
// Make economics valid. Ideally, we'd use
29+
// NetworkEconomics::with_default_values(), but many tests rely on
30+
// NetworkEconomics::default() (not the same!).
31+
let economics = governance_proto.economics.as_mut().unwrap();
32+
economics.max_proposals_to_keep_per_topic = 100;
33+
economics.neurons_fund_economics = Some(NeuronsFundEconomics::with_default_values());
34+
economics.voting_power_economics = Some(VotingPowerEconomics::with_default_values());
35+
2636
Self { governance_proto }
2737
}
2838

0 commit comments

Comments
 (0)