Skip to content

Commit

Permalink
Merge branch 'fraccaman/sdk-rpc-queries' (#2400)
Browse files Browse the repository at this point in the history
* origin/fraccaman/sdk-rpc-queries:
  added pgf parameters rpc
  added proposal result query to sdk, refactor
  added total supply router/rpc method
  • Loading branch information
tzemanovic committed Jan 16, 2024
2 parents 732bbb6 + c90ac1c commit 77936d8
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 51 deletions.
54 changes: 10 additions & 44 deletions crates/apps/src/lib/client/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1164,53 +1164,19 @@ pub async fn query_proposal_result(
if args.proposal_id.is_some() {
let proposal_id =
args.proposal_id.expect("Proposal id should be defined.");
let proposal = if let Some(proposal) =
query_proposal_by_id(context.client(), proposal_id)
.await
.unwrap()
{
proposal

let proposal_result = namada_sdk::rpc::query_proposal_result(
context.client(),
proposal_id,
)
.await;

if let Ok(Some(proposal_result)) = proposal_result {
display_line!(context.io(), "Proposal Id: {} ", proposal_id);
display_line!(context.io(), "{:4}{}", "", proposal_result);
} else {
edisplay_line!(context.io(), "Proposal {} not found.", proposal_id);
return;
};

let proposal_result_key =
governance_storage::get_proposal_result_key(proposal_id);
let proposal_result =
// Try to directly query the result in storage first
match query_storage_value(context.client(), &proposal_result_key).await {
Ok(result) => result,
Err(_) => {
// If failure, run the tally
let is_author_steward = query_pgf_stewards(context.client())
.await
.iter()
.any(|steward| steward.address.eq(&proposal.author));
let tally_type = proposal.get_tally_type(is_author_steward);
let total_voting_power = get_total_staked_tokens(
context.client(),
proposal.voting_end_epoch,
)
.await;

let votes = compute_proposal_votes(
context.client(),
proposal_id,
proposal.voting_end_epoch,
)
.await;

compute_proposal_result(
votes,
total_voting_power,
tally_type,
)
}
};

display_line!(context.io(), "Proposal Id: {} ", proposal_id);
display_line!(context.io(), "{:4}{}", "", proposal_result);
} else {
let proposal_folder = args.proposal_folder.expect(
"The argument --proposal-folder is required with --offline.",
Expand Down
15 changes: 14 additions & 1 deletion crates/governance/src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::storage::proposal::{
InitProposalData, ProposalType, StorageProposal, VoteProposalData,
};
use crate::storage::vote::ProposalVote;
use crate::utils::Vote;
use crate::utils::{ProposalResult, Vote};
use crate::ADDRESS as governance_address;

/// A proposal creation transaction.
Expand Down Expand Up @@ -267,3 +267,16 @@ where
storage.read(&key)?.expect("Parameter should be defined.");
Ok(max_proposal_period)
}

/// Get governance proposal result stored in storage if proposal ended
pub fn get_proposal_result<S>(
storage: &S,
proposal_id: u64,
) -> storage_api::Result<Option<ProposalResult>>
where
S: storage_api::StorageRead,
{
let key = governance_keys::get_proposal_result_key(proposal_id);
let proposal_result: Option<ProposalResult> = storage.read(&key)?;
Ok(proposal_result)
}
44 changes: 44 additions & 0 deletions crates/governance/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,50 @@ pub struct ProposalVotes {
pub delegator_voting_power: HashMap<Address, HashMap<Address, VotePower>>,
}

impl ProposalVotes {
/// Add vote correspoding to a validator
pub fn add_validator(
&mut self,
address: &Address,
voting_power: VotePower,
vote: TallyVote,
) {
match self.validators_vote.insert(address.clone(), vote) {
// the value was update, this should never happen
None => {
self.validator_voting_power
.insert(address.clone(), voting_power);
}
_ => tracing::error!(
"Duplicate vote for validator {}",
address.clone()
),
};
}

/// Add vote corresponding to a delegator
pub fn add_delegator(
&mut self,
address: &Address,
validator_address: &Address,
voting_power: VotePower,
vote: TallyVote,
) {
match self.delegators_vote.insert(address.clone(), vote) {
None => {
self.delegator_voting_power
.entry(address.clone())
.or_default()
.insert(validator_address.clone(), voting_power);
}
_ => tracing::error!(
"Duplicate vote for delegator {}",
address.clone()
),
}
}
}

/// Compute the result of a proposal
pub fn compute_proposal_result(
votes: ProposalVotes,
Expand Down
1 change: 0 additions & 1 deletion crates/sdk/src/queries/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ router! {SHELL,
// Conversion state access - read conversion
( "conversions" ) -> BTreeMap<AssetType, ConversionWithoutPath> = read_conversions,


// Conversion state access - read conversion
( "masp_reward_tokens" ) -> BTreeMap<String, Address> = masp_reward_tokens,

Expand Down
15 changes: 14 additions & 1 deletion crates/sdk/src/queries/vp/governance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use namada_governance::parameters::GovernanceParameters;
use namada_governance::storage::proposal::StorageProposal;
use namada_governance::utils::Vote;
use namada_governance::utils::{ProposalResult, Vote};
use namada_state::{DBIter, StorageHasher, DB};

use crate::queries::types::RequestCtx;
Expand All @@ -12,6 +12,7 @@ router! {GOV,
( "proposal" / [id: u64 ] ) -> Option<StorageProposal> = proposal_id,
( "proposal" / [id: u64 ] / "votes" ) -> Vec<Vote> = proposal_id_votes,
( "parameters" ) -> GovernanceParameters = parameters,
( "stored_proposal_result" / [id: u64] ) -> Option<ProposalResult> = proposal_result,
}

/// Query the provided proposal id
Expand Down Expand Up @@ -48,3 +49,15 @@ where
{
namada_governance::storage::get_parameters(ctx.wl_storage)
}

/// Get the governance proposal result stored in storage
fn proposal_result<D, H, V, T>(
ctx: RequestCtx<'_, D, H, V, T>,
id: u64,
) -> storage_api::Result<Option<ProposalResult>>
where
D: 'static + DB + for<'iter> DBIter<'iter> + Sync,
H: 'static + StorageHasher + Sync,
{
storage_api::governance::get_proposal_result(ctx.wl_storage, id)
}
15 changes: 14 additions & 1 deletion crates/sdk/src/queries/vp/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
use namada_core::types::address::Address;
use namada_core::types::token;
use namada_state::{DBIter, StorageHasher, DB};
use namada_token::read_denom;
use namada_token::{read_denom, read_total_supply};

use crate::queries::RequestCtx;

router! {TOKEN,
( "denomination" / [addr: Address] ) -> Option<token::Denomination> = denomination,
( "total_supply" / [addr: Address] ) -> Option<token::Amount> = total_supply,
}

/// Get the number of decimal places (in base 10) for a
Expand All @@ -24,6 +25,18 @@ where
read_denom(ctx.wl_storage, &addr)
}

/// Get the total supply for a token address
fn total_supply<D, H, V, T>(
ctx: RequestCtx<'_, D, H, V, T>,
addr: Address,
) -> storage_api::Result<token::Amount>
where
D: 'static + DB + for<'iter> DBIter<'iter> + Sync,
H: 'static + StorageHasher + Sync,
{
read_total_supply(ctx.wl_storage, &addr)
}

#[cfg(any(test, feature = "async-client"))]
pub mod client_only_methods {
use borsh::BorshDeserialize;
Expand Down
101 changes: 98 additions & 3 deletions crates/sdk/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ use namada_core::types::{storage, token};
use namada_governance::parameters::GovernanceParameters;
use namada_governance::pgf::storage::steward::StewardDetail;
use namada_governance::storage::proposal::StorageProposal;
use namada_governance::utils::Vote;
use namada_governance::utils::{
compute_proposal_result, ProposalResult, ProposalVotes, Vote,
};
use namada_ibc::storage::{
ibc_denom_key, ibc_denom_key_prefix, is_ibc_denom_key,
};
Expand Down Expand Up @@ -177,6 +179,14 @@ pub async fn get_token_balance<C: crate::queries::Client + Sync>(
)
}

/// Query token total supply;
pub async fn get_token_total_supply<C: crate::queries::Client + Sync>(
client: &C,
token: &Address,
) -> Result<Option<token::Amount>, error::Error> {
convert_response::<C, _>(RPC.vp().token().total_supply(client, token).await)
}

/// Check if the given address is a known validator.
pub async fn is_validator<C: crate::queries::Client + Sync>(
client: &C,
Expand Down Expand Up @@ -935,6 +945,84 @@ pub async fn get_public_key_at<C: crate::queries::Client + Sync>(
}
}

/// Query the proposal result
pub async fn query_proposal_result<C: crate::queries::Client + Sync>(
client: &C,
proposal_id: u64,
) -> Result<Option<ProposalResult>, Error> {
let proposal = query_proposal_by_id(client, proposal_id).await?;
let proposal = if let Some(proposal) = proposal {
proposal
} else {
return Ok(None);
};
let stored_proposal_result = convert_response::<C, Option<ProposalResult>>(
RPC.vp().gov().proposal_result(client, &proposal_id).await,
)?;
let proposal_result = match stored_proposal_result {
Some(proposal_result) => proposal_result,
None => {
let tally_epoch = proposal.voting_end_epoch;

let is_author_pgf_steward =
is_steward(client, &proposal.author).await;
let votes = query_proposal_votes(client, proposal_id)
.await
.unwrap_or_default();
let tally_type = proposal.get_tally_type(is_author_pgf_steward);
let total_staked_token =
get_total_staked_tokens(client, tally_epoch)
.await
.unwrap_or_default();

let mut proposal_votes = ProposalVotes::default();

for vote in votes {
match vote.is_validator() {
true => {
let voting_power = get_validator_stake(
client,
tally_epoch,
&vote.validator,
)
.await
.unwrap_or_default();

proposal_votes.add_validator(
&vote.validator,
voting_power,
vote.data.into(),
);
}
false => {
let voting_power = get_bond_amount_at(
client,
&vote.delegator,
&vote.validator,
tally_epoch,
)
.await
.unwrap_or_default();

proposal_votes.add_delegator(
&vote.delegator,
&vote.validator,
voting_power,
vote.data.into(),
);
}
}
}
compute_proposal_result(
proposal_votes,
total_staked_token,
tally_type,
)
}
};
Ok(Some(proposal_result))
}

/// Query a validator's unbonds for a given epoch
pub async fn query_and_print_unbonds(
context: &impl Namada,
Expand Down Expand Up @@ -1005,14 +1093,21 @@ pub async fn query_unbond_with_slashing<C: crate::queries::Client + Sync>(
)
}

/// Get the givernance parameters
/// Get the governance parameters
pub async fn query_governance_parameters<C: crate::queries::Client + Sync>(
client: &C,
) -> GovernanceParameters {
unwrap_client_response::<C, _>(RPC.vp().gov().parameters(client).await)
}

/// Get the givernance parameters
/// Get the public good fundings parameters
pub async fn query_pgf_parameters<C: crate::queries::Client + Sync>(
client: &C,
) -> PgfParameters {
unwrap_client_response::<C, _>(RPC.vp().pgf().parameters(client).await)
}

/// Get all the votes of a proposal
pub async fn query_proposal_votes<C: crate::queries::Client + Sync>(
client: &C,
proposal_id: u64,
Expand Down

0 comments on commit 77936d8

Please sign in to comment.