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

Update config extensions #185

Merged
merged 8 commits into from
Sep 19, 2022
Merged
Show file tree
Hide file tree
Changes from 3 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
68 changes: 61 additions & 7 deletions contracts/tgrade-valset/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use std::convert::{TryFrom, TryInto};
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{
to_binary, Addr, Binary, BlockInfo, CustomQuery, Decimal, Deps, DepsMut, Env, MessageInfo,
Order, QueryRequest, Reply, StdError, StdResult, Timestamp, WasmMsg,
to_binary, Addr, Binary, BlockInfo, Coin, CustomQuery, Decimal, Deps, DepsMut, Env,
MessageInfo, Order, QueryRequest, Reply, StdError, StdResult, Timestamp, WasmMsg,
};

use cw2::set_contract_version;
Expand All @@ -20,7 +20,7 @@ use tg_bindings::{
Pubkey, TgradeMsg, TgradeQuery, TgradeSudoMsg, ToAddress, ValidatorDiff, ValidatorUpdate,
ValidatorVoteResponse,
};
use tg_utils::{JailingDuration, SlashMsg, ADMIN};
use tg_utils::{Duration, JailingDuration, SlashMsg, ADMIN};

use crate::error::ContractError;
use crate::migration::{migrate_jailing_period, migrate_verify_validators};
Expand All @@ -32,9 +32,9 @@ use crate::msg::{
};
use crate::rewards::pay_block_rewards;
use crate::state::{
export, import, operators, Config, EpochInfo, OperatorInfo, ValidatorInfo, ValidatorSlashing,
ValsetState, BLOCK_SIGNERS, CONFIG, EPOCH, JAIL, VALIDATORS, VALIDATOR_SLASHING,
VALIDATOR_START_HEIGHT,
export, import, operators, Config, DistributionContract, EpochInfo, OperatorInfo,
ValidatorInfo, ValidatorSlashing, ValsetState, BLOCK_SIGNERS, CONFIG, EPOCH, JAIL, VALIDATORS,
VALIDATOR_SLASHING, VALIDATOR_START_HEIGHT,
};

// version info for migration info
Expand Down Expand Up @@ -164,7 +164,28 @@ pub fn execute(
ExecuteMsg::UpdateConfig {
min_points,
max_validators,
} => execute_update_config(deps, info, min_points, max_validators),
scaling,
epoch_reward,
fee_percentage,
auto_unjail,
double_sign_slash_ratio,
distribution_contracts,
verify_validators,
offline_jail_duration,
} => execute_update_config(
deps,
info,
min_points,
max_validators,
scaling,
epoch_reward,
fee_percentage,
auto_unjail,
double_sign_slash_ratio,
distribution_contracts,
verify_validators,
offline_jail_duration,
),

ExecuteMsg::RegisterValidatorKey { pubkey, metadata } => {
execute_register_validator_key(deps, env, info, pubkey, metadata)
Expand All @@ -182,11 +203,20 @@ pub fn execute(
}
}

#[allow(clippy::too_many_arguments)]
fn execute_update_config<Q: CustomQuery>(
deps: DepsMut<Q>,
info: MessageInfo,
min_points: Option<u64>,
max_validators: Option<u32>,
scaling: Option<u32>,
epoch_reward: Option<Coin>,
fee_percentage: Option<Decimal>,
auto_unjail: Option<bool>,
double_sign_slash_ratio: Option<Decimal>,
distribution_contracts: Option<Vec<DistributionContract>>,
verify_validators: Option<bool>,
offline_jail_duration: Option<Duration>,
) -> Result<Response, ContractError> {
ADMIN.assert_admin(deps.as_ref(), &info.sender)?;

Expand All @@ -197,6 +227,30 @@ fn execute_update_config<Q: CustomQuery>(
if let Some(max_validators) = max_validators {
cfg.max_validators = max_validators;
}
if let Some(scaling) = scaling {
cfg.scaling = Option::from(scaling);
}
if let Some(epoch_reward) = epoch_reward {
cfg.epoch_reward = epoch_reward;
}
if let Some(fee_percentage) = fee_percentage {
cfg.fee_percentage = fee_percentage;
}
if let Some(auto_unjail) = auto_unjail {
cfg.auto_unjail = auto_unjail;
}
if let Some(double_sign_slash_ratio) = double_sign_slash_ratio {
cfg.double_sign_slash_ratio = double_sign_slash_ratio;
}
if let Some(distribution_contracts) = distribution_contracts {
cfg.distribution_contracts = distribution_contracts;
}
if let Some(verify_validators) = verify_validators {
cfg.verify_validators = verify_validators;
}
if let Some(offline_jail_duration) = offline_jail_duration {
cfg.offline_jail_duration = offline_jail_duration;
}
Ok(cfg)
})?;

Expand Down
39 changes: 39 additions & 0 deletions contracts/tgrade-valset/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,47 @@ pub enum ExecuteMsg {
},
/// Alter config values
UpdateConfig {
/// minimum points needed by an address in `membership` to be considered for the validator set.
/// 0-point members are always filtered out.
min_points: Option<u64>,
/// The maximum number of validators that can be included in the Tendermint validator set.
/// If there are more validators than slots, we select the top N by membership points
/// descending.
max_validators: Option<u32>,
/// A scaling factor to multiply tg4-engagement points to produce the tendermint validator power
scaling: Option<u32>,
/// Total reward paid out each epoch. This will be split among all validators during the last
/// epoch.
/// (epoch_reward.amount * 86_400 * 30 / epoch_length) is reward tokens to mint each month.
/// Ensure this is sensible in relation to the total token supply.
epoch_reward: Option<Coin>,
/// Percentage of total accumulated fees which is subtracted from tokens minted as a rewards.
/// 50% as default. To disable this feature just set it to 0 (which effectively means that fees
/// doesn't affect the per epoch reward).
fee_percentage: Option<Decimal>,
/// Flag determining if validators should be automatically unjailed after jailing period, false
/// by default.
auto_unjail: Option<bool>,

/// Validators who are caught double signing are jailed forever and their bonded tokens are
/// slashed based on this value.
double_sign_slash_ratio: Option<Decimal>,

/// Addresses where part of the reward for non-validators is sent for further distribution. These are
/// required to handle the `Distribute {}` message (eg. tg4-engagement contract) which would
/// distribute the funds sent with this message.
/// The sum of ratios here has to be in the [0, 1] range. The remainder is sent to validators via the
/// rewards contract.
distribution_contracts: Option<Vec<DistributionContract>>,

/// If this is enabled, signed blocks are watched for, and if a validator fails to sign any blocks
/// in a string of a number of blocks (typically 1000 blocks), they are jailed.
verify_validators: Option<bool>,

/// The duration to jail a validator for in case they don't sign any blocks for a period of time,
/// if `verify_validators` is enabled.
/// After the jailing period, they will be jailed again if not signing blocks, ad infinitum.
offline_jail_duration: Option<Duration>,
},
/// Links info.sender (operator) to this Tendermint consensus key.
/// The operator cannot re-register another key.
Expand Down
11 changes: 10 additions & 1 deletion contracts/tgrade-valset/src/multitest/suite.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::helpers::addr_to_pubkey;
use crate::state::{Config, ValsetState};
use crate::state::{Config, DistributionContract, ValsetState};
use crate::test_helpers::{mock_metadata, mock_pubkey};
use crate::{msg::*, state::ValidatorInfo};
use anyhow::{bail, Result as AnyResult};
Expand Down Expand Up @@ -589,13 +589,22 @@ impl Suite {
executor: &str,
min_points: impl Into<Option<u64>>,
max_validators: impl Into<Option<u32>>,
distribution_contracts: impl Into<Option<Vec<DistributionContract>>>,
) -> AnyResult<AppResponse> {
self.app.execute_contract(
Addr::unchecked(executor),
self.valset.clone(),
&ExecuteMsg::UpdateConfig {
min_points: min_points.into(),
max_validators: max_validators.into(),
scaling: None,
epoch_reward: None,
fee_percentage: None,
auto_unjail: None,
double_sign_slash_ratio: None,
distribution_contracts: distribution_contracts.into(),
verify_validators: None,
offline_jail_duration: None,
},
&[],
)
Expand Down
43 changes: 39 additions & 4 deletions contracts/tgrade-valset/src/multitest/update_config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use cosmwasm_std::{Addr, Decimal};
use cw_controllers::AdminError;

use crate::error::ContractError;
use crate::multitest::suite::Suite;
use crate::state::DistributionContract;

use super::suite::SuiteBuilder;

Expand All @@ -16,39 +19,71 @@ fn update_cfg() {
assert_eq!(cfg.max_validators, 6);
assert_eq!(cfg.min_points, 3);

suite.update_config(&admin, Some(5), Some(10)).unwrap();
suite
.update_config(
&admin,
Some(5),
Some(10),
vec![DistributionContract {
contract: Addr::unchecked("contract1"),
ratio: Decimal::percent(15),
}],
)
.unwrap();

let cfg = suite.config().unwrap();
assert_eq!(cfg.max_validators, 10);
assert_eq!(cfg.min_points, 5);
assert_eq!(
cfg.distribution_contracts,
vec![DistributionContract {
contract: Addr::unchecked("contract1"),
ratio: Decimal::percent(15)
}]
);
}

#[test]
fn none_values_do_not_alter_cfg() {
let mut suite = SuiteBuilder::new()
let mut suite: Suite = SuiteBuilder::new()
.with_max_validators(6)
.with_min_points(3)
.with_distribution(Decimal::percent(50), &[("engagement1", 20)], None)
.build();
let admin = suite.admin().to_string();

let cfg = suite.config().unwrap();
assert_eq!(cfg.max_validators, 6);
assert_eq!(cfg.min_points, 3);
assert_eq!(
cfg.distribution_contracts,
vec![DistributionContract {
contract: Addr::unchecked("contract1"),
ratio: Decimal::percent(50)
}]
);

suite.update_config(&admin, None, None).unwrap();
suite.update_config(&admin, None, None, None).unwrap();

// Make sure the values haven't changed.
let cfg = suite.config().unwrap();
assert_eq!(cfg.max_validators, 6);
assert_eq!(cfg.min_points, 3);
assert_eq!(
cfg.distribution_contracts,
vec![DistributionContract {
contract: Addr::unchecked("contract1"),
ratio: Decimal::percent(50)
}]
);
}

#[test]
fn non_admin_cannot_update_cfg() {
let mut suite = SuiteBuilder::new().build();

let err = suite
.update_config("random fella", Some(5), Some(10))
.update_config("random fella", Some(5), Some(10), None)
.unwrap_err();
assert_eq!(
ContractError::AdminError(AdminError::NotAdmin {}),
Expand Down
7 changes: 3 additions & 4 deletions contracts/tgrade-valset/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ pub struct Config {
pub min_points: u64,
/// The maximum number of validators that can be included in the Tendermint validator set.
/// If there are more validators than slots, we select the top N by membership points
/// descending. (In case of ties at the last slot, select by "first" tendermint pubkey
/// lexicographically sorted).
/// descending. In case of ties at the last slot, the first (oldest) validator wins.
pub max_validators: u32,
/// A scaling factor to multiply tg4-engagement points to produce the tendermint validator power
pub scaling: Option<u32>,
Expand Down Expand Up @@ -61,8 +60,8 @@ pub struct Config {
/// in a string of a number of blocks (typically 1000 blocks), they are jailed.
pub verify_validators: bool,

/// The duration to jail a validator for in case they don't sign their first epoch
/// boundary block. After the period, they have to pass verification again, ad infinitum.
/// The duration to jail a validator for in case they don't sign any blocks for a period of time.
/// After the jailing period, they will be jailed again if not signing, ad infinitum.
pub offline_jail_duration: Duration,
}

Expand Down