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

Fix bug of same-epoch stake deactivation after stake redelegation #32606

Merged
merged 3 commits into from
Sep 25, 2023

Conversation

HaoranYi
Copy link
Contributor

@HaoranYi HaoranYi commented Jul 24, 2023

Problem

Normally, activated stake has to wait at least one epoch after being deactivated, before it becomes deactivated and withdrawable.

However, there is a bug in redelegation which could lead to same-epoch stake deactivation after stake redelegation. By redelegating the activated stake to another validator and deactivating the redelegated stake, the stake becomes deactivated and withdrawable in the same epoch.

Part of #31876

Summary of Changes

Fix bug of same-epoch stake deactivation after stake redelegation

Fixes #

@HaoranYi HaoranYi changed the title fix stake deactivation in the same epoch after redelegation bug Fix stake deactivation in the same epoch after redelegation bug Jul 24, 2023
@HaoranYi HaoranYi changed the title Fix stake deactivation in the same epoch after redelegation bug Fix bug of same-epoch stake deatviation after stake delegation Jul 24, 2023
@codecov
Copy link

codecov bot commented Jul 24, 2023

Codecov Report

Merging #32606 (7c45985) into master (57e78a1) will increase coverage by 0.0%.
Report is 8 commits behind head on master.
The diff coverage is 96.4%.

@@           Coverage Diff            @@
##           master   #32606    +/-   ##
========================================
  Coverage    81.9%    81.9%            
========================================
  Files         798      798            
  Lines      216577   216980   +403     
========================================
+ Hits       177537   177874   +337     
- Misses      39040    39106    +66     

Copy link
Member

@mvines mvines left a comment

Choose a reason for hiding this comment

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

this PR is so much clearer now that the other refactoring landed earlier!
it looks like there's no test for the condition we're fixing here though, we'll definitely want to add one, or several, to demonstrate the fix

@HaoranYi
Copy link
Contributor Author

this PR is so much clearer now that the other refactoring landed earlier! it looks like there's no test for the condition we're fixing here though, we'll definitely want to add one, or several, to demonstrate the fix

Yeah. Added.

@mvines mvines changed the title Fix bug of same-epoch stake deatviation after stake delegation Fix bug of same-epoch stake deactivation after stake delegation Jul 24, 2023
@t-nelson
Copy link
Contributor

can we spruce up the description to indicate that this bug is restricted to the Redelegate operation?

@HaoranYi HaoranYi changed the title Fix bug of same-epoch stake deactivation after stake delegation Fix bug of same-epoch stake deactivation after stake redelegation Jul 24, 2023
programs/stake/src/stake_state.rs Outdated Show resolved Hide resolved
@@ -2320,3 +2320,757 @@ fn test_stake_minimum_delegation() {
let result = process_command(&config);
assert!(matches!(result, Ok(..)));
}

#[test]
fn test_stake_redelegation_then_deactivation_withdraw_not_permitted() {
Copy link
Contributor

@t-nelson t-nelson Jul 25, 2023

Choose a reason for hiding this comment

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

these don't seem to be testing any new cli behavior, they'd be better implemented against SolanaTestValidator TestValidator (or even Bank) directly than with all of the superfluous cli plumbing in the middle

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 am not sure that I understand your comments.

  1. Inside cli/tests, it uses TestValidator class. Is that not the SolanaTestValidator?
  2. The test scenario for this bug is very complex. It involves multiple stake accounts and votes accounts, and a sequence of very specific actions, i.e. delegate, redelegate, merge, deactivate, withdraw etc. It also requires stake_history mutation. I am not sure how this can be modeled on just bank itself. I think bank tests are more suitable to test individual instruction. Do you know any examples on bank test to model stake deactivation, activation and withdraw?
  3. It seems like cli/stake.rs is where we are testing all other existing scenarios of stake manipulation, such as redelegation, withdraw etc. Therefore, I feel it is natural to extend those tests to cover the new behavior.

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 saying that the cli crate is not a test framework, that these tests belong elsewhere and implemented without the cli details

Copy link
Contributor Author

@HaoranYi HaoranYi Jul 25, 2023

Choose a reason for hiding this comment

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

To me, the cli/tests looks more or less like a test framework. It has been used to test stake, vote, transfer, and other programs. And it has very useful test_util.rs, which make it very convenient to model complex test scenario there.

I don't know if we should "reinvent the wheel" to write another test framework to model the lifetime of a test validator. Or maybe I am missing something about the other test framework?

Do you know where the other test framework/utility is, which could be used to better model these tests, and where should those tests be?

Copy link
Contributor

Choose a reason for hiding this comment

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

To me, the cli/tests looks more or less like a test framework.

this is a function of those tests existing before TestValidator and us for some reason being very paranoid about cli behaving as expected. most, if not all of them should really be modernized at some point to avoid leading folks astray

I don't know if we should "reinvent the wheel" to write another test framework to model the lifetime of a test validator.

we don't need to, that's literally what TestValidator was for. the tests will be similar but won't a) live under the totally unrelated cli crate and b) have all of the superfluous cli machination in the way and confounding tests. you'll grab an RpcClient handle from the TestValidator instance, build the txes up and rpc_client.send_and_confirm_transaction() your way to victory. these should probably live under programs/stake, either a new tests directory or if one of existing source files seems appropriate

it should be a red flag when tests are being added to a crate that was otherwise unaffected by the change set that something isn't right organizationally

Copy link
Contributor

Choose a reason for hiding this comment

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

which has a separate crate for tests

oh thank god. i missed that this wasn't implementing the tests directory as a standalone crate. just realized i was about to get screwed by the instruction processor being globbed into BUILTINS. this is The Way ™️

the program crates like solana-stake-program should function like normal program crates

generally agree, but there's a bunch of crap in this program crate that makes zero sense. even have comments about being external helpers with uses listed that are... not the program itself!

Copy link
Contributor

Choose a reason for hiding this comment

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

It seems that moving the stake tests out of cli is not as straightforward as it looks.

How about keeping these 3 tests in cli for this PR, and moving all stake tests out of cli in a separated follow-up PR after we fixes the circular dependencies issue?

take a crack at making the tests dir a crate as jon proposes first. doing the easy thing our of impatience is how the code got into the shape it is today. that followup pr rarely happens

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok. I will create a new test crate solana-stake-program-tests for those tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

generally agree, but there's a bunch of crap in this program crate that makes zero sense. even have comments about being external helpers with uses listed that are... not the program itself!

That's totally fair... the native program crates are probably the most problematic with dependencies. We could eventually make it a policy that all native stuff goes into the sdk, but I would prefer to thin out the sdk whenever possible.

Note: I'm the one who moved a lot of the stake types into the sdk in the first place while developing stake pools, because I didn't think to use target_os guards in solana-stake-program, so I bear a lot of the responsibility there 😓

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

sdk/program/src/stake/state.rs Outdated Show resolved Hide resolved
sdk/program/src/stake/state.rs Outdated Show resolved Hide resolved
@HaoranYi HaoranYi marked this pull request as draft July 26, 2023 01:25
@HaoranYi HaoranYi marked this pull request as ready for review July 26, 2023 02:05
@HaoranYi HaoranYi force-pushed the stake_fix branch 5 times, most recently from 0583f66 to 1a2de7b Compare July 28, 2023 01:43
Copy link
Contributor

@joncinque joncinque left a comment

Choose a reason for hiding this comment

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

We're getting really close! Just a few bits to make the tests better, which @t-nelson can shoot down if he wishes.

Cargo.toml Outdated
@@ -88,6 +88,7 @@ members = [
"sdk/program",
"send-transaction-service",
"stake-accounts",
"stake-program-test",
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: let's put this in programs/stake-tests for consistency with address lookup table tests

@@ -0,0 +1,21 @@
[package]
name = "stake-program-test"
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:

Suggested change
name = "stake-program-test"
name = "solana-stake-program-tests"

license = { workspace = true }
edition = { workspace = true }

[dependencies]
Copy link
Contributor

Choose a reason for hiding this comment

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

These should all be dev-dependencies

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: you should be able to delete this file

Copy link
Contributor

Choose a reason for hiding this comment

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

Although it's better factored, I don't think this addresses @t-nelson 's point about using the CLI as a test framework, since it's still using CLI commands.

Rather than CLI helpers, how about using solana-program-test? To make it easier, you can copy these helpers for creating vote accounts https://github.com/solana-labs/solana-program-library/blob/8f1a8c6e9c58c8710f0655d5e54d3f07bfacf003/stake-pool/single-pool/tests/helpers/mod.rs#L349 and stake accounts https://github.com/solana-labs/solana-program-library/blob/8f1a8c6e9c58c8710f0655d5e54d3f07bfacf003/stake-pool/single-pool/tests/helpers/stake.rs#L66

I know it's annoying to change the test framework, but it'll make maintenance a lot easier going forward, and you can use warp_to_slot on ProgramTestContext to simulate advancing epochs, which will make the test run much more quickly.

Copy link
Contributor Author

@HaoranYi HaoranYi Jul 28, 2023

Choose a reason for hiding this comment

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

yeah. I was debating about whether to use or not to use those CLI helpers yesterday too. Basically, the cli functions used in the tests are just wrappers for rpc_clients. We can certainly reimplement those helpers for tests, which would end up inlining all the cli functions in those tests. They wouldn't make much difference except duplicated code.

I will take a look at the program-test and see if rewrite those tests in program-tests is better.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done! Rewrite the tests in program-test.

Copy link
Contributor

@joncinque joncinque left a comment

Choose a reason for hiding this comment

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

The test looks great! Mainly some nits around it, so this is extremely close

program-test/tests/test_utils.rs Outdated Show resolved Hide resolved
program-test/tests/test_utils.rs Outdated Show resolved Hide resolved
program-test/tests/test_utils.rs Outdated Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I usually dislike vague names for helper files, how about something like setup.rs since there's just setup stuff in there?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

program-test/tests/stake.rs Outdated Show resolved Hide resolved
program-test/tests/stake.rs Outdated Show resolved Hide resolved
program-test/tests/stake.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@joncinque joncinque left a comment

Choose a reason for hiding this comment

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

Looks setup.rs wasn't committed, but the rest of the changes look good

@HaoranYi
Copy link
Contributor Author

HaoranYi commented Aug 4, 2023

Looks setup.rs wasn't committed, but the rest of the changes look good

oops. added.

joncinque
joncinque previously approved these changes Aug 4, 2023
Copy link
Contributor

@joncinque joncinque left a comment

Choose a reason for hiding this comment

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

Looks great! Be sure to get at least one more approval on this since it touches the stake program

@HaoranYi HaoranYi requested a review from t-nelson August 4, 2023 21:58
@github-actions github-actions bot added the stale [bot only] Added to stale content; results in auto-close after a week. label Aug 28, 2023
@HaoranYi
Copy link
Contributor Author

@t-nelson Can you review this again and let me know if you are okay with this PR? Thanks!

@github-actions github-actions bot removed the stale [bot only] Added to stale content; results in auto-close after a week. label Aug 30, 2023
@github-actions github-actions bot added the stale [bot only] Added to stale content; results in auto-close after a week. label Sep 14, 2023
@HaoranYi HaoranYi requested a review from joncinque September 20, 2023 18:19
@github-actions github-actions bot removed the stale [bot only] Added to stale content; results in auto-close after a week. label Sep 21, 2023
joncinque
joncinque previously approved these changes Sep 22, 2023
Copy link
Contributor

@joncinque joncinque left a comment

Choose a reason for hiding this comment

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

Still looks good to me!

program-test/tests/warp.rs Outdated Show resolved Hide resolved
Comment on lines 190 to 203
#[tokio::test]
async fn test_stake_redelegation_then_deactivation_withdraw_not_permitted() {
test_stake_redelegation_pending_activation(PendingStakeActivationTestFlag::NoMerge).await
}

#[tokio::test]
async fn test_stake_redelegation_then_merge_active_then_deactivation_withdraw_not_permitted() {
test_stake_redelegation_pending_activation(PendingStakeActivationTestFlag::MergeActive).await
}

#[tokio::test]
async fn test_stake_redelegation_then_merge_inactive_then_deactivation_withdraw_not_permitted() {
test_stake_redelegation_pending_activation(PendingStakeActivationTestFlag::MergeInactive).await
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: rather than having all of these, you could have them all as separate test_cases

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good idea. updated.

joncinque
joncinque previously approved these changes Sep 25, 2023
@CriesofCarrots CriesofCarrots self-requested a review September 25, 2023 19:13
Copy link
Contributor

@CriesofCarrots CriesofCarrots left a comment

Choose a reason for hiding this comment

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

One suggestion to move sysvar load

programs/stake/src/stake_instruction.rs Show resolved Hide resolved
programs/stake/src/stake_state.rs Outdated Show resolved Hide resolved
#[tokio::test]
async fn stake_rewards_from_warp() {
// Initialize and start the test network
let program_test = ProgramTest::default();
let mut context = program_test.start_with_context().await;

context.warp_to_slot(100).unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

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

To be clear, Trent isn't objecting to the change, just requesting that the move and the edit be noted in separate commits. So the commits in this PR might be something like:

  1. Add deactivate_stake() helper
  2. Return error when feature activated and StakeFlag set
  3. Add stake_flag unit test
  4. Move setup_stake to its own mod
  5. Only warp in warp.rs tests
  6. Add stake.rs tests

I don't want to bog this down in a reorg, so just a consideration for next time.

program-test/tests/stake.rs Outdated Show resolved Hide resolved
HaoranYi added 3 commits September 25, 2023 20:11
add tests

refactor common code into fn

avoid early return

add feature gate for the new stake redelegate behavior

move stake tests out of cli

add stake-program-test crate

reimplemnt stake test with program-test

remove stake-program-test crate

reviews

add setup.rs

remove clippy

reveiws
@HaoranYi HaoranYi merged commit d25d53e into solana-labs:master Sep 25, 2023
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants