diff --git a/.changelog/unreleased/improvements/3442-limit-pgf-stewards.md b/.changelog/unreleased/improvements/3442-limit-pgf-stewards.md new file mode 100644 index 0000000000..35094192f6 --- /dev/null +++ b/.changelog/unreleased/improvements/3442-limit-pgf-stewards.md @@ -0,0 +1,2 @@ +- Enforce an upper limit on the number of PGF stewards allowed to exist at a + given time. ([\#3442](https://github.com/anoma/namada/pull/3442)) \ No newline at end of file diff --git a/.github/workflows/triggerable-antithesis.yml b/.github/workflows/triggerable-antithesis.yml index 70bb66984d..d0c9d7746c 100644 --- a/.github/workflows/triggerable-antithesis.yml +++ b/.github/workflows/triggerable-antithesis.yml @@ -1,4 +1,4 @@ -name: Triggerable Antithesis workflow +name: Triggerable Antithesis on: workflow_dispatch: @@ -30,4 +30,4 @@ jobs: username: ${{ secrets.ANTITHESIS_USER_NAME }} password: ${{ secrets.ANTITHESIS_PASSWORD }} github_token: ${{ secrets.GITHUB_TOKEN }} - images: namada-config:${{ github.event.inputs.namada_docker_tag }},namada-genesis:${{ github.event.inputs.namada_docker_tag }},namada:${{ github.event.inputs.namada_docker_tag }},namada:${{ github.event.inputs.namada_docker_tag }}-inst,namada-scenario-tester:${{ github.event.inputs.scenario_tester_docker_tag }} \ No newline at end of file + images: namada-config:${{ github.event.inputs.namada_docker_tag }},namada-genesis:${{ github.event.inputs.namada_docker_tag }},namada:${{ github.event.inputs.namada_docker_tag }},namada-scenario-tester:${{ github.event.inputs.scenario_tester_docker_tag }} \ No newline at end of file diff --git a/crates/apps_lib/src/config/genesis/chain.rs b/crates/apps_lib/src/config/genesis/chain.rs index 1027e84aa5..827d7df9ad 100644 --- a/crates/apps_lib/src/config/genesis/chain.rs +++ b/crates/apps_lib/src/config/genesis/chain.rs @@ -752,6 +752,7 @@ impl FinalizedParameters { stewards: pgf_params.stewards, pgf_inflation_rate: pgf_params.pgf_inflation_rate, stewards_inflation_rate: pgf_params.stewards_inflation_rate, + maximum_number_of_stewards: pgf_params.maximum_number_of_stewards, }; Self { parameters, diff --git a/crates/apps_lib/src/config/genesis/templates.rs b/crates/apps_lib/src/config/genesis/templates.rs index c99f75f101..e21e1fc1c7 100644 --- a/crates/apps_lib/src/config/genesis/templates.rs +++ b/crates/apps_lib/src/config/genesis/templates.rs @@ -465,6 +465,8 @@ pub struct PgfParams { pub pgf_inflation_rate: Dec, /// The pgf stewards inflation rate pub stewards_inflation_rate: Dec, + /// The maximum allowed number of PGF stewards at any time + pub maximum_number_of_stewards: u64, #[serde(default)] #[serde(skip_serializing)] #[cfg(test)] @@ -904,6 +906,8 @@ pub fn validate_parameters( stewards: pgf_params.stewards, pgf_inflation_rate: pgf_params.pgf_inflation_rate, stewards_inflation_rate: pgf_params.stewards_inflation_rate, + maximum_number_of_stewards: pgf_params + .maximum_number_of_stewards, valid: Default::default(), }, eth_bridge_params, diff --git a/crates/governance/src/pgf/parameters.rs b/crates/governance/src/pgf/parameters.rs index 171bc91200..533497ce12 100644 --- a/crates/governance/src/pgf/parameters.rs +++ b/crates/governance/src/pgf/parameters.rs @@ -34,6 +34,8 @@ pub struct PgfParameters { pub pgf_inflation_rate: Dec, /// The pgf stewards inflation rate pub stewards_inflation_rate: Dec, + /// The maximum number of pgf stewards at once + pub maximum_number_of_stewards: u64, } impl Default for PgfParameters { @@ -42,6 +44,7 @@ impl Default for PgfParameters { stewards: BTreeSet::default(), pgf_inflation_rate: Dec::new(10, 2).unwrap(), stewards_inflation_rate: Dec::new(1, 2).unwrap(), + maximum_number_of_stewards: 5, } } } @@ -56,6 +59,7 @@ impl PgfParameters { stewards, pgf_inflation_rate, stewards_inflation_rate, + maximum_number_of_stewards, } = self; for steward in stewards { @@ -71,6 +75,11 @@ impl PgfParameters { let steward_inflation_rate_key = pgf_storage::get_steward_inflation_rate_key(); - storage.write(&steward_inflation_rate_key, stewards_inflation_rate) + storage.write(&steward_inflation_rate_key, stewards_inflation_rate)?; + + let maximum_number_of_stewards_key = + pgf_storage::get_maximum_number_of_pgf_steward_key(); + storage + .write(&maximum_number_of_stewards_key, maximum_number_of_stewards) } } diff --git a/crates/governance/src/pgf/storage/keys.rs b/crates/governance/src/pgf/storage/keys.rs index dcdee44d83..846b5c95ad 100644 --- a/crates/governance/src/pgf/storage/keys.rs +++ b/crates/governance/src/pgf/storage/keys.rs @@ -14,6 +14,7 @@ struct Keys { fundings: &'static str, pgf_inflation_rate: &'static str, steward_inflation_rate: &'static str, + maximum_number_of_stewards: &'static str, } /// Obtain a storage key for stewards key @@ -94,6 +95,13 @@ pub fn get_pgf_inflation_rate_key() -> Key { .expect("Cannot obtain a storage key") } +/// Get key for maximum number of pgf stewards +pub fn get_maximum_number_of_pgf_steward_key() -> Key { + Key::from(ADDRESS.to_db_key()) + .push(&Keys::VALUES.maximum_number_of_stewards.to_owned()) + .expect("Cannot obtain a storage key") +} + /// Get key for inflation rate key pub fn get_steward_inflation_rate_key() -> Key { Key::from(ADDRESS.to_db_key()) diff --git a/crates/node/src/shell/governance.rs b/crates/node/src/shell/governance.rs index 545e8f6d9f..e924f2e16f 100644 --- a/crates/node/src/shell/governance.rs +++ b/crates/node/src/shell/governance.rs @@ -158,14 +158,20 @@ where GovernanceEvent::passed_proposal(id, true, result) } ProposalType::PGFSteward(stewards) => { - let _result = execute_pgf_steward_proposal( + let result = execute_pgf_steward_proposal( &mut shell.state, stewards, )?; tracing::info!( - "Governance proposal (pgf stewards){} has been \ - executed and passed.", - id + "Governance proposal #{} for PGF stewards has \ + been executed. {}.", + id, + if result { + "State changes have been applied successfully" + } else { + "FAILURE trying to apply the state changes - \ + no state change occurred" + } ); GovernanceEvent::passed_proposal(id, false, false) @@ -461,18 +467,41 @@ fn execute_pgf_steward_proposal( where S: StorageRead + StorageWrite, { - for action in stewards { - match action { - AddRemove::Add(address) => { - pgf_storage::stewards_handle().insert( - storage, - address.to_owned(), - StewardDetail::base(address), - )?; - } - AddRemove::Remove(address) => { - pgf_storage::stewards_handle().remove(storage, &address)?; - } + let maximum_number_of_pgf_steward_key = + pgf_storage::get_maximum_number_of_pgf_steward_key(); + let maximum_number_of_pgf_steward = storage + .read::(&maximum_number_of_pgf_steward_key)? + .expect( + "Pgf parameter maximum_number_of_pgf_steward must be in storage", + ); + + // First, remove the appropriate addresses + for address in stewards.iter().filter_map(|action| match action { + AddRemove::Add(_) => None, + AddRemove::Remove(address) => Some(address), + }) { + pgf_storage::stewards_handle().remove(storage, address)?; + } + + // Then add new addresses + let mut steward_count = pgf_storage::stewards_handle().len(storage)?; + for address in stewards.iter().filter_map(|action| match action { + AddRemove::Add(address) => Some(address), + AddRemove::Remove(_) => None, + }) { + #[allow(clippy::arithmetic_side_effects)] + if steward_count + 1 > maximum_number_of_pgf_steward { + return Ok(false); + } + pgf_storage::stewards_handle().insert( + storage, + address.to_owned(), + StewardDetail::base(address.to_owned()), + )?; + + #[allow(clippy::arithmetic_side_effects)] + { + steward_count += 1; } } diff --git a/genesis/localnet/parameters.toml b/genesis/localnet/parameters.toml index f0ccb838a0..17c03b9c62 100644 --- a/genesis/localnet/parameters.toml +++ b/genesis/localnet/parameters.toml @@ -100,6 +100,8 @@ stewards = [ pgf_inflation_rate = "0.1" # The pgf stewards inflation rate stewards_inflation_rate = "0.01" +# The maximum number of pgf stewards +maximum_number_of_stewards = 5 # IBC parameters [ibc_params] diff --git a/genesis/starter/parameters.toml b/genesis/starter/parameters.toml index b9c0b0a625..6889b8125e 100644 --- a/genesis/starter/parameters.toml +++ b/genesis/starter/parameters.toml @@ -97,6 +97,8 @@ stewards = [] pgf_inflation_rate = "0.1" # The pgf stewards inflation rate stewards_inflation_rate = "0.01" +# The maximum number of pgf stewards +maximum_number_of_stewards = 5 # IBC parameters [ibc_params]