-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Conversation
Codecov Report
@@ Coverage Diff @@
## master #32606 +/- ##
========================================
Coverage 81.9% 81.9%
========================================
Files 798 798
Lines 216577 216980 +403
========================================
+ Hits 177537 177874 +337
- Misses 39040 39106 +66 |
There was a problem hiding this 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
Yeah. Added. |
can we spruce up the description to indicate that this bug is restricted to the |
cli/tests/stake.rs
Outdated
@@ -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() { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
- Inside cli/tests, it uses
TestValidator
class. Is that not theSolanaTestValidator
? - 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?
- 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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
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 ofcli
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 😓
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
0583f66
to
1a2de7b
Compare
There was a problem hiding this 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", |
There was a problem hiding this comment.
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
stake-program-test/Cargo.toml
Outdated
@@ -0,0 +1,21 @@ | |||
[package] | |||
name = "stake-program-test" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
name = "stake-program-test" | |
name = "solana-stake-program-tests" |
stake-program-test/Cargo.toml
Outdated
license = { workspace = true } | ||
edition = { workspace = true } | ||
|
||
[dependencies] |
There was a problem hiding this comment.
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
stake-program-test/src/lib.rs
Outdated
There was a problem hiding this comment.
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
stake-program-test/tests/stake.rs
Outdated
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
.
There was a problem hiding this 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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
There was a problem hiding this 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
oops. added. |
There was a problem hiding this 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
@t-nelson Can you review this again and let me know if you are okay with this PR? Thanks! |
There was a problem hiding this 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/stake.rs
Outdated
#[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 | ||
} |
There was a problem hiding this comment.
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_case
s
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea. updated.
a9bbf47
to
c2b889e
Compare
There was a problem hiding this 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
#[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(); |
There was a problem hiding this comment.
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:
- Add
deactivate_stake()
helper - Return error when feature activated and StakeFlag set
- Add stake_flag unit test
- Move
setup_stake
to its own mod - Only warp in warp.rs tests
- Add stake.rs tests
I don't want to bog this down in a reorg, so just a consideration for next time.
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
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 #