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

Governance fixes rebase #501

Merged
merged 37 commits into from
Oct 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9a61587
[fix]: governance overflow, proposal validation
Fraccaman May 26, 2022
2aee155
[feat]: added total votes to query
Fraccaman May 26, 2022
9a08d61
[misc]: clippy, fmt
Fraccaman May 26, 2022
afe779a
[fix]: clippy, fmt
Fraccaman May 27, 2022
ee303e5
[fix]: clippy, fmt
Fraccaman May 27, 2022
124b2d9
[fix]: bad validation condition
Fraccaman May 27, 2022
4373e5d
[fix]: governance vp author address, proposal submission validation
Fraccaman May 27, 2022
f7cb4c0
[feat]: vote transaction validation
Fraccaman May 27, 2022
4903744
[fix]: error println
Fraccaman May 27, 2022
3ca66b2
[misc]: clippy, fmt
Fraccaman May 27, 2022
9450054
[fix]: e2e test
Fraccaman May 27, 2022
6cbf9dc
[fix]: e2e test
Fraccaman May 27, 2022
ecbefd0
Fixes e2e tests
grarco May 30, 2022
e49d8b0
Fixes test artifacts folder persistence
grarco May 31, 2022
2a385bd
[fix]: votes accumulation
Fraccaman Jun 13, 2022
20de724
[misc]: remove logs
Fraccaman Jun 13, 2022
2423a02
Fixes `safe_exit` call only if `force` is not set
grarco Jun 14, 2022
a6bf03a
Speeds up testing
grarco Jun 14, 2022
0a7f0f5
fmt and fix clippy
tzemanovic Jul 1, 2022
a8f6c64
Rename `Treasury` to `SlashFund`
grarco Sep 20, 2022
ff951ff
Skip tx whitelist for proposal code
grarco Sep 21, 2022
4a3d097
Use proposal `end_epoch` instead of `start_epoch` for voting power
grarco Sep 21, 2022
de18d0f
Removes `max_proposal_fund_transfer` parameter
grarco Sep 21, 2022
172a930
Adds `max_proposal_period` governance parameter
grarco Sep 21, 2022
4b22589
[misc] rebase
Sep 22, 2022
3863caa
fix proposal_submission e2e test
Sep 22, 2022
860e175
fix display proposal result in cli
Sep 22, 2022
8e8af7a
[ci] wasm checksums update
github-actions[bot] Sep 22, 2022
7119de4
Fixes specs
grarco Sep 22, 2022
467fcc8
[ci] wasm checksums update
github-actions[bot] Sep 23, 2022
88513f6
Refactors governance e2e tests
grarco Sep 23, 2022
218f45d
Uses `end_epoch` in `query_proposal_result`
grarco Sep 23, 2022
5b34bff
Misc refactoring
grarco Sep 23, 2022
e4ab8c9
fix e2e tests
Sep 26, 2022
c0e18b9
fix e2e tests
Sep 26, 2022
ccfa965
changelog: add #501
grarco Sep 26, 2022
7e3cf90
[ci] wasm checksums update
github-actions[bot] Sep 26, 2022
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
2 changes: 2 additions & 0 deletions .changelog/unreleased/improvements/467-governance-fixes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Fixed governance parameters, tally, tx whitelist and renamed treasury
([#467](https://github.com/anoma/namada/issues/467))
216 changes: 124 additions & 92 deletions apps/src/lib/client/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use async_std::path::PathBuf;
use async_std::prelude::*;
use borsh::BorshDeserialize;
use itertools::Itertools;
use namada::ledger::governance::parameters::GovParams;
use namada::ledger::governance::storage as gov_storage;
use namada::ledger::governance::utils::Votes;
use namada::ledger::parameters::{storage as param_storage, EpochDuration};
Expand All @@ -21,10 +22,10 @@ use namada::ledger::pos::types::{
use namada::ledger::pos::{
self, is_validator_slashes_key, BondId, Bonds, PosParams, Slash, Unbonds,
};
use namada::ledger::treasury::storage as treasury_storage;
use namada::types::address::Address;
use namada::types::governance::{
OfflineProposal, OfflineVote, ProposalVote, TallyResult,
OfflineProposal, OfflineVote, ProposalResult, ProposalVote, TallyResult,
VotePower,
};
use namada::types::key::*;
use namada::types::storage::{Epoch, PrefixValue};
Expand Down Expand Up @@ -302,28 +303,25 @@ pub async fn query_proposal_result(

match args.proposal_id {
Some(id) => {
let start_epoch_key = gov_storage::get_voting_start_epoch_key(id);
let end_epoch_key = gov_storage::get_voting_end_epoch_key(id);
let start_epoch =
query_storage_value::<Epoch>(&client, &start_epoch_key).await;
let end_epoch =
query_storage_value::<Epoch>(&client, &end_epoch_key).await;

match (start_epoch, end_epoch) {
(Some(start_epoch), Some(end_epoch)) => {
match end_epoch {
Some(end_epoch) => {
if current_epoch > end_epoch {
let votes =
get_proposal_votes(&client, start_epoch, id).await;
get_proposal_votes(&client, end_epoch, id).await;
let proposal_result =
compute_tally(&client, start_epoch, votes).await;
compute_tally(&client, end_epoch, votes).await;
println!("Proposal: {}", id);
println!("{:4}Result: {}", "", proposal_result);
} else {
eprintln!("Proposal is still in progress.");
cli::safe_exit(1)
}
}
_ => {
None => {
eprintln!("Error while retriving proposal.");
cli::safe_exit(1)
}
Expand All @@ -347,7 +345,14 @@ pub async fn query_proposal_result(
if entry.file_name().eq(&"proposal")
{
is_proposal_present = true
} else {
} else if entry
.file_name()
.to_string_lossy()
.starts_with("proposal-vote-")
{
// Folder may contain other
// files than just the proposal
// and the votes
files.insert(entry.path());
}
}
Expand All @@ -369,8 +374,8 @@ pub async fn query_proposal_result(

if !is_proposal_present {
eprintln!(
"The folder must contain a the offline \
proposal in a file named proposal"
"The folder must contain the offline proposal \
in a file named \"proposal\""
);
cli::safe_exit(1)
}
Expand Down Expand Up @@ -414,7 +419,10 @@ pub async fn query_proposal_result(
}
};
} else {
eprintln!("Either id or offline should be used as arguments.");
eprintln!(
"Either --proposal-id or --data-path should be provided \
as arguments."
);
cli::safe_exit(1)
}
}
Expand All @@ -427,45 +435,8 @@ pub async fn query_protocol_parameters(
) {
let client = HttpClient::new(args.query.ledger_address).unwrap();

println!("Goveranance parameters");
let key = gov_storage::get_max_proposal_code_size_key();
let max_proposal_code_size = query_storage_value::<u64>(&client, &key)
.await
.expect("Parameter should be definied.");
println!(
"{:4}Max. proposal code size: {}",
"", max_proposal_code_size
);

let key = gov_storage::get_max_proposal_content_key();
let max_proposal_content = query_storage_value::<u64>(&client, &key)
.await
.expect("Parameter should be definied.");
println!(
"{:4}Max. proposal content size: {}",
"", max_proposal_content
);

let key = gov_storage::get_min_proposal_fund_key();
let min_proposal_fund = query_storage_value::<Amount>(&client, &key)
.await
.expect("Parameter should be definied.");
println!("{:4}Min. proposal funds: {}", "", min_proposal_fund);

let key = gov_storage::get_min_proposal_grace_epoch_key();
let min_proposal_grace_epoch = query_storage_value::<u64>(&client, &key)
.await
.expect("Parameter should be definied.");
println!(
"{:4}Min. proposal grace epoch: {}",
"", min_proposal_grace_epoch
);

let key = gov_storage::get_min_proposal_period_key();
let min_proposal_period = query_storage_value::<u64>(&client, &key)
.await
.expect("Parameter should be definied.");
println!("{:4}Min. proposal period: {}", "", min_proposal_period);
let gov_parameters = get_governance_parameters(&client).await;
println!("Governance Parameters\n {:4}", gov_parameters);

println!("Protocol parameters");
let key = param_storage::get_epoch_storage_key();
Expand Down Expand Up @@ -499,16 +470,6 @@ pub async fn query_protocol_parameters(
.expect("Parameter should be definied.");
println!("{:4}Transactions whitelist: {:?}", "", tx_whitelist);

println!("Treasury parameters");
let key = treasury_storage::get_max_transferable_fund_key();
let max_transferable_amount = query_storage_value::<Amount>(&client, &key)
.await
.expect("Parameter should be definied.");
println!(
"{:4}Max. transferable amount: {}",
"", max_transferable_amount
);

println!("PoS parameters");
let key = pos::params_key();
let pos_params = query_storage_value::<PosParams>(&client, &key)
Expand Down Expand Up @@ -1558,9 +1519,11 @@ pub async fn get_proposal_votes(
query_storage_prefix::<ProposalVote>(client.clone(), vote_prefix_key)
.await;

let mut yay_validators: HashMap<Address, Amount> = HashMap::new();
let mut yay_delegators: HashMap<Address, Amount> = HashMap::new();
let mut nay_delegators: HashMap<Address, Amount> = HashMap::new();
let mut yay_validators: HashMap<Address, VotePower> = HashMap::new();
let mut yay_delegators: HashMap<Address, HashMap<Address, VotePower>> =
HashMap::new();
let mut nay_delegators: HashMap<Address, HashMap<Address, VotePower>> =
HashMap::new();

if let Some(vote_iter) = vote_iter {
for (key, vote) in vote_iter {
Expand All @@ -1587,9 +1550,15 @@ pub async fn get_proposal_votes(
.await;
if let Some(amount) = delegator_token_amount {
if vote.is_yay() {
yay_delegators.insert(voter_address, amount);
let entry =
yay_delegators.entry(voter_address).or_default();
entry
.insert(validator_address, VotePower::from(amount));
} else {
nay_delegators.insert(voter_address, amount);
let entry =
nay_delegators.entry(voter_address).or_default();
entry
.insert(validator_address, VotePower::from(amount));
}
}
}
Expand All @@ -1612,9 +1581,11 @@ pub async fn get_proposal_offline_votes(

let proposal_hash = proposal.compute_hash();

let mut yay_validators: HashMap<Address, Amount> = HashMap::new();
let mut yay_delegators: HashMap<Address, Amount> = HashMap::new();
let mut nay_delegators: HashMap<Address, Amount> = HashMap::new();
let mut yay_validators: HashMap<Address, VotePower> = HashMap::new();
let mut yay_delegators: HashMap<Address, HashMap<Address, VotePower>> =
HashMap::new();
let mut nay_delegators: HashMap<Address, HashMap<Address, VotePower>> =
HashMap::new();

for path in files {
let file = File::open(&path).expect("Proposal file must exist.");
Expand Down Expand Up @@ -1669,9 +1640,17 @@ pub async fn get_proposal_offline_votes(
"Delegation key should contain validator address.",
);
if proposal_vote.vote.is_yay() {
yay_delegators.insert(validator_address, amount);
let entry = yay_delegators
.entry(proposal_vote.address.clone())
.or_default();
entry
.insert(validator_address, VotePower::from(amount));
} else {
nay_delegators.insert(validator_address, amount);
let entry = nay_delegators
.entry(proposal_vote.address.clone())
.or_default();
entry
.insert(validator_address, VotePower::from(amount));
}
}
}
Expand All @@ -1690,7 +1669,7 @@ pub async fn compute_tally(
client: &HttpClient,
epoch: Epoch,
votes: Votes,
) -> TallyResult {
) -> ProposalResult {
let validators = get_all_validators(client, epoch).await;
let total_stacked_tokens =
get_total_staked_tokes(client, epoch, &validators).await;
Expand All @@ -1701,29 +1680,43 @@ pub async fn compute_tally(
nay_delegators,
} = votes;

let mut total_yay_stacked_tokens = Amount::from(0);
let mut total_yay_stacked_tokens = VotePower::from(0_u64);
for (_, amount) in yay_validators.clone().into_iter() {
total_yay_stacked_tokens += amount;
}

// YAY: Add delegator amount whose validator didn't vote / voted nay
for (validator_address, amount) in yay_delegators.into_iter() {
if !yay_validators.contains_key(&validator_address) {
total_yay_stacked_tokens += amount;
for (_, vote_map) in yay_delegators.iter() {
for (validator_address, vote_power) in vote_map.iter() {
if !yay_validators.contains_key(validator_address) {
total_yay_stacked_tokens += vote_power;
}
}
}

// NAY: Remove delegator amount whose validator validator vote yay
for (validator_address, amount) in nay_delegators.into_iter() {
if yay_validators.contains_key(&validator_address) {
total_yay_stacked_tokens -= amount;
for (_, vote_map) in nay_delegators.iter() {
for (validator_address, vote_power) in vote_map.iter() {
if yay_validators.contains_key(validator_address) {
total_yay_stacked_tokens -= vote_power;
}
}
}

if 3 * total_yay_stacked_tokens >= 2 * total_stacked_tokens {
TallyResult::Passed
if total_yay_stacked_tokens >= (total_stacked_tokens / 3) * 2 {
ProposalResult {
result: TallyResult::Passed,
total_voting_power: total_stacked_tokens,
total_yay_power: total_yay_stacked_tokens,
total_nay_power: 0,
}
} else {
TallyResult::Rejected
ProposalResult {
result: TallyResult::Rejected,
total_voting_power: total_stacked_tokens,
total_yay_power: total_yay_stacked_tokens,
total_nay_power: 0,
}
}
}

Expand Down Expand Up @@ -1788,8 +1781,8 @@ pub async fn get_total_staked_tokes(
client: &HttpClient,
epoch: Epoch,
validators: &[Address],
) -> token::Amount {
let mut total = Amount::from(0);
) -> VotePower {
let mut total = VotePower::from(0_u64);

for validator in validators {
total += get_validator_stake(client, epoch, validator).await;
Expand All @@ -1801,7 +1794,7 @@ async fn get_validator_stake(
client: &HttpClient,
epoch: Epoch,
validator: &Address,
) -> token::Amount {
) -> VotePower {
let total_voting_power_key = pos::validator_total_deltas_key(validator);
let total_voting_power = query_storage_value::<pos::ValidatorTotalDeltas>(
client,
Expand All @@ -1810,11 +1803,9 @@ async fn get_validator_stake(
.await
.expect("Total deltas should be defined");
let epoched_total_voting_power = total_voting_power.get(epoch);
if let Some(epoched_total_voting_power) = epoched_total_voting_power {
token::Amount::from_change(epoched_total_voting_power)
} else {
token::Amount::from(0)
}

VotePower::try_from(epoched_total_voting_power.unwrap_or_default())
.unwrap_or_default()
}

pub async fn get_delegators_delegation(
Expand All @@ -1836,3 +1827,44 @@ pub async fn get_delegators_delegation(
}
delegation_addresses
}

pub async fn get_governance_parameters(client: &HttpClient) -> GovParams {
let key = gov_storage::get_max_proposal_code_size_key();
let max_proposal_code_size = query_storage_value::<u64>(client, &key)
.await
.expect("Parameter should be definied.");

let key = gov_storage::get_max_proposal_content_key();
let max_proposal_content_size = query_storage_value::<u64>(client, &key)
.await
.expect("Parameter should be definied.");

let key = gov_storage::get_min_proposal_fund_key();
let min_proposal_fund = query_storage_value::<Amount>(client, &key)
.await
.expect("Parameter should be definied.");

let key = gov_storage::get_min_proposal_grace_epoch_key();
let min_proposal_grace_epochs = query_storage_value::<u64>(client, &key)
.await
.expect("Parameter should be definied.");

let key = gov_storage::get_min_proposal_period_key();
let min_proposal_period = query_storage_value::<u64>(client, &key)
.await
.expect("Parameter should be definied.");

let key = gov_storage::get_max_proposal_period_key();
let max_proposal_period = query_storage_value::<u64>(client, &key)
.await
.expect("Parameter should be definied.");

GovParams {
min_proposal_fund: u64::from(min_proposal_fund),
max_proposal_code_size,
min_proposal_period,
max_proposal_period,
max_proposal_content_size,
min_proposal_grace_epochs,
}
}
Loading