Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Add redeem_vote_credits to runtime #7910

Merged

Conversation

rob-solana
Copy link
Contributor

Problem

RedeemVoteCredits has a number of problems:

Somebody must issue this instruction every MAX_EPOCH_CREDITS_HISTORY epochs for each stake/vote account or rewards evaporate.
Reward point values are computed based on the latest epoch, which can produce confusing and hard to understand results as this example from TdS DR6 shows:
After the first 24 hours of idling, redeeming votes
using a ~1 SOL stake produced ~6221 SOL in voter rewards. Redeeming
that same stake 12 hours later produced ~54 SOL in voter rewards. The reason
for this huge reward drop is because the total stake increased from 435 SOL to 25695
SOL in those 12 hours, so the credit point value was much smaller.
The stake/vote accounts/programs as well as runtime contains code/data bloat that exists only to enable RedeemVoteCredits in its current form.
The first two points highlight the unintentional game that will be played around RedeemVoteCredits: if you see observe stake decreasing in the cluster than you're better off delaying RedeemVoteCredits if possible to capitalize on the increasing credit point value. But don't delay too long or you'll lost it all. Worse, RedeemVoteCredits can be run by anybody so others can inflict less desirable credit point values on you.

The alternative is to dispense of RedeemVoteCredits entirely, and have banks automatically redeem vote credits at the end of each epoch for all parties.

Summary of Changes

add redeem_vote_credits to runtime

CC #7835

@rob-solana rob-solana force-pushed the Move-redeem_vote_credits-into-runtime branch 2 times, most recently from d575773 to c33b229 Compare January 22, 2020 02:24
@codecov
Copy link

codecov bot commented Jan 22, 2020

Codecov Report

❗ No coverage uploaded for pull request base (master@0230746). Click here to learn what that means.
The diff coverage is 97%.

@@           Coverage Diff            @@
##             master   #7910   +/-   ##
========================================
  Coverage          ?     82%           
========================================
  Files             ?     244           
  Lines             ?   52684           
  Branches          ?       0           
========================================
  Hits              ?   43233           
  Misses            ?    9451           
  Partials          ?       0

/// iterate over all stakes, redeem vote credits for each stake we can
/// successfully load and parse, return total payout
fn pay_validator_rewards(&self, validator_point_value: f64) -> u64 {
let stake_history = self.stakes.read().unwrap().history().clone();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the clone?

Copy link
Contributor Author

@rob-solana rob-solana Jan 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the self.store() below needs a write lock on self.stakes, so if I hold a ref to the stake_history, I hold a read lock and get a deadlock

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't inline it? Maybe I'm missing a loop that makes that impractical.

 stake.calculate_rewards(
                                            validator_point_value,
                                            &vote_state,
                                            Some(&self.stakes.read().unwrap().history()),
                                        )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's exactly what I had that caused deadlock ;)

.map(
|(
stake_pubkey,
Delegation {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about just calling this delegation and using delegation.voter_pubkey below?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the vote_pubkey form looked better, matched stake_pubkey. voter_pubkey is an ancient name, and changing it perturbs cli, rpc

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of this style, but I suppose it's just personal preference. I don't feel strongly that it needs to change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it and prefer your style

},
)| {
match (
self.get_account(&stake_pubkey),
Copy link
Contributor

@garious garious Jan 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you return zero in all the edge cases, how about moving all this code into a function that returns an Option, so that you can get rid of all the nested blocks:

let mut stake_state = self.get_account(&stake_pubkey)?.state().ok()?;
let mut vote_state = self.get_account(&vote_pubkey)?.state().ok()?;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when I moved the meat of the function into a separate function, I ended up with a 7 or 8 parameter function...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like a strong indictor something needs to be done here. Maybe multiple functions!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered collecting what needed to be stored to flatten out the code. I also tried a single, 4-parameter match but ran afoul of the borrow checker.

},
)
.sum()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

much of testing is covered by test_bank_update_rewards(). bit that's missing is balance update verifications

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it though? This thing has a whole lot of branches.

Copy link
Contributor Author

@rob-solana rob-solana Jan 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it has essentially 1 branch: whether or not there's meaningful rewards to redeem (tested to death in the stake program). All the corner cases are there to handle the types and not abort.

maybe I should replace all the matches with simple unwrap() or expect(). there are no valid cases where information coming out of bank.stakes can disagree with what's in the accounts_db.

@rob-solana rob-solana force-pushed the Move-redeem_vote_credits-into-runtime branch 3 times, most recently from 6229578 to fe17b9e Compare January 22, 2020 07:25
garious
garious previously approved these changes Jan 22, 2020
Copy link
Contributor

@garious garious left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@rob-solana rob-solana force-pushed the Move-redeem_vote_credits-into-runtime branch from fe17b9e to ed8d6f3 Compare January 22, 2020 17:48
@mergify mergify bot dismissed garious’s stale review January 22, 2020 18:21

Pull request has been modified.

@rob-solana rob-solana force-pushed the Move-redeem_vote_credits-into-runtime branch from ed8d6f3 to 48694ee Compare January 22, 2020 18:31
@rob-solana rob-solana merged commit ce70d6e into solana-labs:master Jan 22, 2020
@rob-solana rob-solana deleted the Move-redeem_vote_credits-into-runtime branch January 22, 2020 20:21
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants