Skip to content

Commit

Permalink
Merge branch 'origin/tomas/pos-bonds-query-reuse' (#1518)
Browse files Browse the repository at this point in the history
* origin/tomas/pos-bonds-query-reuse:
  changelog: add #1518
  app/client/rpc: use enriched bonds and unbonds query
  shared/rpc: add bonds and unbonds details query enriched with extras
  • Loading branch information
Fraccaman committed Jun 14, 2023
2 parents 6ac1fe7 + ca2f53b commit c1c4a64
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 53 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- PoS: make a re-usable bonds and unbonds details query.
([\#1518](https://github.com/anoma/namada/pull/1518))
75 changes: 29 additions & 46 deletions apps/src/lib/client/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ use namada::ledger::pos::{
self, BondId, BondsAndUnbondsDetail, CommissionPair, PosParams, Slash,
};
use namada::ledger::queries::RPC;
use namada::ledger::rpc::{query_epoch, TxResponse};
use namada::ledger::rpc::{
enriched_bonds_and_unbonds, query_epoch, TxResponse,
};
use namada::ledger::storage::ConversionState;
use namada::ledger::wallet::{AddressVpType, Wallet};
use namada::proof_of_stake::types::WeightedValidator;
Expand Down Expand Up @@ -1264,29 +1266,18 @@ pub async fn query_bonds<C: namada::ledger::queries::Client + Sync>(
_wallet: &mut Wallet<CliWalletUtils>,
args: args::QueryBonds,
) -> std::io::Result<()> {
let _epoch = query_and_print_epoch(client).await;
let epoch = query_and_print_epoch(client).await;

let source = args.owner;
let validator = args.validator;

let stdout = io::stdout();
let mut w = stdout.lock();

let bonds_and_unbonds: pos::types::BondsAndUnbondsDetails =
unwrap_client_response::<C, pos::types::BondsAndUnbondsDetails>(
RPC.vp()
.pos()
.bonds_and_unbonds(client, &source, &validator)
.await,
);
let mut bonds_total: token::Amount = 0.into();
let mut bonds_total_slashed: token::Amount = 0.into();
let mut unbonds_total: token::Amount = 0.into();
let mut unbonds_total_slashed: token::Amount = 0.into();
let mut total_withdrawable: token::Amount = 0.into();
for (bond_id, details) in bonds_and_unbonds {
let mut total: token::Amount = 0.into();
let mut total_slashed: token::Amount = 0.into();
let bonds_and_unbonds =
enriched_bonds_and_unbonds(client, epoch, &source, &validator).await;

for (bond_id, details) in &bonds_and_unbonds.data {
let bond_type = if bond_id.source == bond_id.validator {
format!("Self-bonds from {}", bond_id.validator)
} else {
Expand All @@ -1296,74 +1287,66 @@ pub async fn query_bonds<C: namada::ledger::queries::Client + Sync>(
)
};
writeln!(w, "{}:", bond_type)?;
for bond in details.bonds {
for bond in &details.data.bonds {
writeln!(
w,
" Remaining active bond from epoch {}: Δ {}",
bond.start, bond.amount
)?;
total += bond.amount;
total_slashed += bond.slashed_amount.unwrap_or_default();
}
if total_slashed != token::Amount::default() {
if details.bonds_total_slashed != token::Amount::default() {
writeln!(
w,
"Active (slashed) bonds total: {}",
total - total_slashed
details.bonds_total_active()
)?;
}
writeln!(w, "Bonds total: {}", total)?;
writeln!(w, "Bonds total: {}", details.bonds_total)?;
writeln!(w)?;
bonds_total += total;
bonds_total_slashed += total_slashed;

let mut withdrawable = token::Amount::default();
if !details.unbonds.is_empty() {
let mut total: token::Amount = 0.into();
let mut total_slashed: token::Amount = 0.into();
if !details.data.unbonds.is_empty() {
let bond_type = if bond_id.source == bond_id.validator {
format!("Unbonded self-bonds from {}", bond_id.validator)
} else {
format!("Unbonded delegations from {}", bond_id.source)
};
writeln!(w, "{}:", bond_type)?;
for unbond in details.unbonds {
total += unbond.amount;
total_slashed += unbond.slashed_amount.unwrap_or_default();
for unbond in &details.data.unbonds {
writeln!(
w,
" Withdrawable from epoch {} (active from {}): Δ {}",
unbond.withdraw, unbond.start, unbond.amount
)?;
}
withdrawable = total - total_slashed;
writeln!(w, "Unbonded total: {}", total)?;

unbonds_total += total;
unbonds_total_slashed += total_slashed;
total_withdrawable += withdrawable;
writeln!(w, "Unbonded total: {}", details.unbonds_total)?;
}
writeln!(w, "Withdrawable total: {}", withdrawable)?;
writeln!(w, "Withdrawable total: {}", details.total_withdrawable)?;
writeln!(w)?;
}
if bonds_total != bonds_total_slashed {
if bonds_and_unbonds.bonds_total != bonds_and_unbonds.bonds_total_slashed {
writeln!(
w,
"All bonds total active: {}",
bonds_total - bonds_total_slashed
bonds_and_unbonds.bonds_total_active()
)?;
}
writeln!(w, "All bonds total: {}", bonds_total)?;
writeln!(w, "All bonds total: {}", bonds_and_unbonds.bonds_total)?;

if unbonds_total != unbonds_total_slashed {
if bonds_and_unbonds.unbonds_total
!= bonds_and_unbonds.unbonds_total_slashed
{
writeln!(
w,
"All unbonds total active: {}",
unbonds_total - unbonds_total_slashed
bonds_and_unbonds.unbonds_total_active()
)?;
}
writeln!(w, "All unbonds total: {}", unbonds_total)?;
writeln!(w, "All unbonds total withdrawable: {}", total_withdrawable)?;
writeln!(w, "All unbonds total: {}", bonds_and_unbonds.unbonds_total)?;
writeln!(
w,
"All unbonds total withdrawable: {}",
bonds_and_unbonds.total_withdrawable
)?;
Ok(())
}

Expand Down
6 changes: 2 additions & 4 deletions shared/src/ledger/queries/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ pub use types::Client;
pub use types::{
EncodedResponseQuery, RequestCtx, RequestQuery, ResponseQuery, Router,
};
use vp::VP;
// Re-export to show in rustdoc!
pub use vp::{Pos, Vp};
use vp::{Vp, VP};

use super::storage::{DBIter, StorageHasher, DB};
use super::storage_api;
Expand All @@ -22,7 +20,7 @@ use crate::types::storage::BlockHeight;
mod router;
mod shell;
mod types;
mod vp;
pub mod vp;

// Most commonly expected patterns should be declared first
router! {RPC,
Expand Down
5 changes: 4 additions & 1 deletion shared/src/ledger/queries/vp/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
//! Queries router and handlers for validity predicates
// Re-export to show in rustdoc!
pub use pos::Pos;
use pos::POS;
mod pos;
pub mod pos;

// Validity predicate queries
router! {VP,
( "pos" ) = (sub POS),
}

/// Client-only methods for the router type are composed from router functions.
#[cfg(any(test, feature = "async-client"))]
pub mod client_only_methods {
#[cfg(not(feature = "mainnet"))]
Expand Down
140 changes: 139 additions & 1 deletion shared/src/ledger/queries/vp/pos.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
//! Queries router and handlers for PoS validity predicate
use std::collections::{HashMap, HashSet};

use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
use namada_core::ledger::storage_api::collections::lazy_map;
use namada_core::ledger::storage_api::OptionExt;
use namada_proof_of_stake::types::{
BondId, BondsAndUnbondsDetails, CommissionPair, Slash, WeightedValidator,
BondId, BondsAndUnbondsDetail, BondsAndUnbondsDetails, CommissionPair,
Slash, WeightedValidator,
};
use namada_proof_of_stake::{
self, below_capacity_validator_set_handle, bond_amount, bond_handle,
Expand Down Expand Up @@ -87,6 +91,46 @@ router! {POS,

}

/// Enriched bonds data with extra information calculated from the data queried
/// from the node.
#[derive(Debug, Clone, BorshDeserialize, BorshSerialize, BorshSchema)]
pub struct Enriched<T> {
/// The queried data
pub data: T,
/// Sum of the bond amounts
pub bonds_total: token::Amount,
/// Sum of the bond slashed amounts
pub bonds_total_slashed: token::Amount,
/// Sum of the unbond amounts
pub unbonds_total: token::Amount,
/// Sum of the unbond slashed amounts
pub unbonds_total_slashed: token::Amount,
/// Sum ofthe withdrawable amounts
pub total_withdrawable: token::Amount,
}

/// Bonds and unbonds with all details (slashes and rewards, if any) grouped by
/// their bond IDs enriched with extra information calculated from the data
/// queried from the node.
pub type EnrichedBondsAndUnbondsDetails =
Enriched<HashMap<BondId, EnrichedBondsAndUnbondsDetail>>;

/// Bonds and unbonds with all details (slashes and rewards, if any) enriched
/// with extra information calculated from the data queried from the node.
pub type EnrichedBondsAndUnbondsDetail = Enriched<BondsAndUnbondsDetail>;

impl<T> Enriched<T> {
/// The bonds amount reduced by slashes
pub fn bonds_total_active(&self) -> token::Amount {
self.bonds_total - self.bonds_total_slashed
}

/// The unbonds amount reduced by slashes
pub fn unbonds_total_active(&self) -> token::Amount {
self.unbonds_total - self.unbonds_total_slashed
}
}

// Handlers that implement the functions via `trait StorageRead`:

/// Find if the given address belongs to a validator account.
Expand Down Expand Up @@ -473,3 +517,97 @@ where
{
namada_proof_of_stake::find_validator_by_raw_hash(ctx.wl_storage, tm_addr)
}

/// Client-only methods for the router type are composed from router functions.
#[cfg(any(test, feature = "async-client"))]
pub mod client_only_methods {
use super::*;
use crate::ledger::queries::{Client, RPC};

impl Pos {
/// Get bonds and unbonds with all details (slashes and rewards, if any)
/// grouped by their bond IDs, enriched with extra information
/// calculated from the data.
pub async fn enriched_bonds_and_unbonds<CLIENT>(
&self,
client: &CLIENT,
current_epoch: Epoch,
source: &Option<Address>,
validator: &Option<Address>,
) -> Result<EnrichedBondsAndUnbondsDetails, <CLIENT as Client>::Error>
where
CLIENT: Client + Sync,
{
let data = RPC
.vp()
.pos()
.bonds_and_unbonds(client, source, validator)
.await?;
Ok(enrich_bonds_and_unbonds(current_epoch, data))
}
}
}

/// Calculate extra information from the bonds and unbonds details.
fn enrich_bonds_and_unbonds(
current_epoch: Epoch,
bonds_and_unbonds: BondsAndUnbondsDetails,
) -> EnrichedBondsAndUnbondsDetails {
let mut bonds_total: token::Amount = 0.into();
let mut bonds_total_slashed: token::Amount = 0.into();
let mut unbonds_total: token::Amount = 0.into();
let mut unbonds_total_slashed: token::Amount = 0.into();
let mut total_withdrawable: token::Amount = 0.into();

let enriched_details: HashMap<BondId, EnrichedBondsAndUnbondsDetail> =
bonds_and_unbonds
.into_iter()
.map(|(bond_id, detail)| {
let mut bond_total: token::Amount = 0.into();
let mut bond_total_slashed: token::Amount = 0.into();
let mut unbond_total: token::Amount = 0.into();
let mut unbond_total_slashed: token::Amount = 0.into();
let mut withdrawable: token::Amount = 0.into();

for bond in &detail.bonds {
bond_total += bond.amount;
bond_total_slashed +=
bond.slashed_amount.unwrap_or_default();
}
for unbond in &detail.unbonds {
unbond_total += unbond.amount;
unbond_total_slashed +=
unbond.slashed_amount.unwrap_or_default();

if current_epoch >= unbond.withdraw {
withdrawable += unbond.amount
- unbond.slashed_amount.unwrap_or_default()
}
}

bonds_total += bond_total;
bonds_total_slashed += bond_total_slashed;
unbonds_total += unbond_total;
unbonds_total_slashed += unbond_total_slashed;
total_withdrawable += withdrawable;

let enriched_detail = EnrichedBondsAndUnbondsDetail {
data: detail,
bonds_total: bond_total,
bonds_total_slashed: bond_total_slashed,
unbonds_total: unbond_total,
unbonds_total_slashed: unbond_total_slashed,
total_withdrawable: withdrawable,
};
(bond_id, enriched_detail)
})
.collect();
EnrichedBondsAndUnbondsDetails {
data: enriched_details,
bonds_total,
bonds_total_slashed,
unbonds_total,
unbonds_total_slashed,
total_withdrawable,
}
}
Loading

0 comments on commit c1c4a64

Please sign in to comment.