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

Pos Reward Updates #2217

Merged
merged 4 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Implement a CLI query for available rewards from a bond,
and improve the bond amount for rewards computation
([\#2217](https://github.com/anoma/namada/pull/2217))
66 changes: 64 additions & 2 deletions apps/src/lib/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ pub mod cmds {
.subcommand(QueryPgf::def().display_order(5))
.subcommand(QueryValidatorState::def().display_order(5))
.subcommand(QueryCommissionRate::def().display_order(5))
.subcommand(QueryRewards::def().display_order(5))
.subcommand(QueryMetaData::def().display_order(5))
// Actions
.subcommand(SignTx::def().display_order(6))
Expand Down Expand Up @@ -315,6 +316,7 @@ pub mod cmds {
let query_bonded_stake =
Self::parse_with_ctx(matches, QueryBondedStake);
let query_slashes = Self::parse_with_ctx(matches, QuerySlashes);
let query_rewards = Self::parse_with_ctx(matches, QueryRewards);
let query_delegations =
Self::parse_with_ctx(matches, QueryDelegations);
let query_find_validator =
Expand Down Expand Up @@ -369,6 +371,7 @@ pub mod cmds {
.or(query_bonds)
.or(query_bonded_stake)
.or(query_slashes)
.or(query_rewards)
.or(query_delegations)
.or(query_find_validator)
.or(query_result)
Expand Down Expand Up @@ -463,6 +466,7 @@ pub mod cmds {
QueryProtocolParameters(QueryProtocolParameters),
QueryPgf(QueryPgf),
QueryValidatorState(QueryValidatorState),
QueryRewards(QueryRewards),
SignTx(SignTx),
GenIbcShieldedTransafer(GenIbcShieldedTransafer),
}
Expand Down Expand Up @@ -1844,6 +1848,28 @@ pub mod cmds {
}
}

#[derive(Clone, Debug)]
pub struct QueryRewards(pub args::QueryRewards<args::CliTypes>);

impl SubCmd for QueryRewards {
const CMD: &'static str = "rewards";

fn parse(matches: &ArgMatches) -> Option<Self> {
matches
.subcommand_matches(Self::CMD)
.map(|matches| QueryRewards(args::QueryRewards::parse(matches)))
}

fn def() -> App {
App::new(Self::CMD)
.about(
"Query the latest rewards available to claim for a given \
delegation (or self-bond).",
)
.add_args::<args::QueryRewards<args::CliTypes>>()
}
}

#[derive(Clone, Debug)]
pub struct QueryDelegations(pub args::QueryDelegations<args::CliTypes>);

Expand Down Expand Up @@ -4826,8 +4852,8 @@ pub mod args {
.arg(VALIDATOR.def().help("Validator address."))
.arg(SOURCE_OPT.def().help(
"Source address for withdrawing from delegations. For \
withdrawing from self-bonds, the validator is also the \
source.",
withdrawing from self-bonds, this arg does not need to \
be supplied.",
))
}
}
Expand Down Expand Up @@ -5552,6 +5578,42 @@ pub mod args {
}
}

impl CliToSdk<QueryRewards<SdkTypes>> for QueryRewards<CliTypes> {
fn to_sdk(self, ctx: &mut Context) -> QueryRewards<SdkTypes> {
QueryRewards::<SdkTypes> {
query: self.query.to_sdk(ctx),
validator: ctx.borrow_chain_or_exit().get(&self.validator),
source: self.source.map(|x| ctx.borrow_chain_or_exit().get(&x)),
}
}
}

impl Args for QueryRewards<CliTypes> {
fn parse(matches: &ArgMatches) -> Self {
let query = Query::parse(matches);
let source = SOURCE_OPT.parse(matches);
let validator = VALIDATOR.parse(matches);
Self {
query,
source,
validator,
}
}

fn def(app: App) -> App {
app.add_args::<Query<CliTypes>>()
.arg(SOURCE_OPT.def().help(
"Source address for the rewards query. For self-bonds, \
this arg does not need to be supplied.",
))
.arg(
VALIDATOR
.def()
.help("Validator address for the rewards query."),
)
}
}

impl Args for QueryDelegations<CliTypes> {
fn parse(matches: &ArgMatches) -> Self {
let query = Query::parse(matches);
Expand Down
11 changes: 11 additions & 0 deletions apps/src/lib/cli/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,17 @@ impl CliApi {
let namada = ctx.to_sdk(&client, io);
rpc::query_slashes(&namada, args).await;
}
Sub::QueryRewards(QueryRewards(mut args)) => {
let client = client.unwrap_or_else(|| {
C::from_tendermint_address(
&mut args.query.ledger_address,
)
});
client.wait_until_node_is_synced(io).await?;
let args = args.to_sdk(&mut ctx);
let namada = ctx.to_sdk(&client, io);
rpc::query_and_print_rewards(&namada, args).await;
}
Sub::QueryDelegations(QueryDelegations(mut args)) => {
let client = client.unwrap_or_else(|| {
C::from_tendermint_address(
Expand Down
29 changes: 27 additions & 2 deletions apps/src/lib/client/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1895,6 +1895,17 @@ pub async fn query_validator_state<
)
}

/// Query and return the available reward tokens corresponding to the bond
pub async fn query_rewards<C: namada::ledger::queries::Client + Sync>(
client: &C,
source: &Option<Address>,
validator: &Address,
) -> token::Amount {
unwrap_client_response::<C, token::Amount>(
RPC.vp().pos().rewards(client, validator, source).await,
)
}

/// Query a validator's state information
pub async fn query_and_print_validator_state<'a>(
context: &impl Namada<'a>,
Expand Down Expand Up @@ -2206,6 +2217,20 @@ pub async fn query_slashes<'a, N: Namada<'a>>(
}
}

pub async fn query_and_print_rewards<'a, N: Namada<'a>>(
context: &N,
args: args::QueryRewards,
) {
let (source, validator) = (args.source, args.validator);

let rewards = query_rewards(context.client(), &source, &validator).await;
display_line!(
context.io(),
"Current rewards available for claim: {} NAM",
rewards.to_string_native()
);
}

pub async fn query_delegations<'a, N: Namada<'a>>(
context: &N,
args: args::QueryDelegations,
Expand Down Expand Up @@ -2628,8 +2653,8 @@ pub async fn query_governance_parameters<
fn unwrap_client_response<C: namada::ledger::queries::Client, T>(
response: Result<T, C::Error>,
) -> T {
response.unwrap_or_else(|_err| {
eprintln!("Error in the query");
response.unwrap_or_else(|err| {
eprintln!("Error in the query: {:?}", err);
cli::safe_exit(1)
})
}
Expand Down
53 changes: 52 additions & 1 deletion apps/src/lib/node/ledger/shell/finalize_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2176,7 +2176,7 @@ mod test_finalize_block {
assert!(rp3 > rp4);
}

/// A unit test for PoS inflationary rewards claiming
/// A unit test for PoS inflationary rewards claiming and querying
#[test]
fn test_claim_rewards() {
let (mut shell, _recv, _, _) = setup_with_cfg(SetupCfg {
Expand Down Expand Up @@ -2252,6 +2252,15 @@ mod test_finalize_block {
advance_epoch(&mut shell, &pkh1, &votes, None);
total_rewards += inflation;

// Query the available rewards
let query_rewards = namada_proof_of_stake::query_reward_tokens(
&shell.wl_storage,
None,
&validator.address,
current_epoch,
)
.unwrap();

// Claim the rewards from the initial epoch
let reward_1 = namada_proof_of_stake::claim_reward_tokens(
&mut shell.wl_storage,
Expand All @@ -2261,8 +2270,20 @@ mod test_finalize_block {
)
.unwrap();
total_claimed += reward_1;
assert_eq!(reward_1, query_rewards);
assert!(is_reward_equal_enough(total_rewards, total_claimed, 1));

// Query the available rewards again and check that it is 0 now after
// the claim
let query_rewards = namada_proof_of_stake::query_reward_tokens(
&shell.wl_storage,
None,
&validator.address,
current_epoch,
)
.unwrap();
assert_eq!(query_rewards, token::Amount::zero());

// Try a claim the next block and ensure we get 0 tokens back
next_block_for_inflation(
&mut shell,
Expand Down Expand Up @@ -2297,6 +2318,15 @@ mod test_finalize_block {
.unwrap();
assert_eq!(unbond_res.sum, unbond_amount);

// Query the available rewards
let query_rewards = namada_proof_of_stake::query_reward_tokens(
&shell.wl_storage,
None,
&validator.address,
current_epoch,
)
.unwrap();

let rew = namada_proof_of_stake::claim_reward_tokens(
&mut shell.wl_storage,
None,
Expand All @@ -2306,6 +2336,7 @@ mod test_finalize_block {
.unwrap();
total_claimed += rew;
assert!(is_reward_equal_enough(total_rewards, total_claimed, 3));
assert_eq!(query_rewards, rew);

// Check the bond amounts for rewards up thru the withdrawable epoch
let withdraw_epoch = current_epoch + params.withdrawable_epoch_offset();
Expand Down Expand Up @@ -2365,6 +2396,15 @@ mod test_finalize_block {
.unwrap();
assert_eq!(withdraw_amount, unbond_amount);

// Query the available rewards
let query_rewards = namada_proof_of_stake::query_reward_tokens(
&shell.wl_storage,
None,
&validator.address,
current_epoch,
)
.unwrap();

// Claim tokens
let reward_2 = namada_proof_of_stake::claim_reward_tokens(
&mut shell.wl_storage,
Expand All @@ -2374,6 +2414,7 @@ mod test_finalize_block {
)
.unwrap();
total_claimed += reward_2;
assert_eq!(query_rewards, reward_2);

// The total rewards claimed should be approximately equal to the total
// minted inflation, minus (unbond_amount / initial_stake) * rewards
Expand All @@ -2384,6 +2425,16 @@ mod test_finalize_block {
let token_uncertainty = uncertainty * lost_rewards;
let token_diff = total_claimed + lost_rewards - total_rewards;
assert!(token_diff < token_uncertainty);

// Query the available rewards to check that they are 0
let query_rewards = namada_proof_of_stake::query_reward_tokens(
&shell.wl_storage,
None,
&validator.address,
current_epoch,
)
.unwrap();
assert_eq!(query_rewards, token::Amount::zero());
}

/// A unit test for PoS inflationary rewards claiming
Expand Down
Loading
Loading