Fix stake split rent-exempt adjustment#13357
Fix stake split rent-exempt adjustment#13357mergify[bot] merged 7 commits intosolana-labs:masterfrom
Conversation
|
Splitting partial amount into empty account (default cli behavior) Before: After: |
|
Splitting complete stake account into account prefunded with rent-exempt reserve of 0.00228288 SOL (I had to edit cli to use the following create-account instruction): Before: After: |
a07174f to
eb8a8db
Compare
|
@rwalker-com , would you be able to take a look at this and see if I'm missing anything? 🙏 |
Codecov Report
@@ Coverage Diff @@
## master #13357 +/- ##
========================================
Coverage 82.0% 82.1%
========================================
Files 378 378
Lines 90042 90286 +244
========================================
+ Hits 73912 74182 +270
+ Misses 16130 16104 -26 |
t-nelson
left a comment
There was a problem hiding this comment.
LGTM! Just a couple comment typoes
eb8a8db to
819b071
Compare
Pull request has been modified.
69d4d2d to
013f40d
Compare
| let lamports_per_byte_year = | ||
| source_meta.rent_exempt_reserve / (source_data_len + ACCOUNT_STORAGE_OVERHEAD); | ||
| lamports_per_byte_year * (split_data_len + ACCOUNT_STORAGE_OVERHEAD) |
There was a problem hiding this comment.
Also, let's cross-ref this out-of-wild rent calculation was unavoidable at Rent in rent.rs. :) So that future engineer working on rent can be wary of this.
There was a problem hiding this comment.
Where would you like to see that comment in rent.rs?
013f40d to
6f399a4
Compare
6f399a4 to
8a99ee3
Compare
| // split account. | ||
| ( | ||
| lamports - meta.rent_exempt_reserve, | ||
| lamports - split_rent_exempt_reserve, |
There was a problem hiding this comment.
Argurably hard to notice, but I think this causes overflow, allowing user to stake around u64::max_size() (if the validator is compiled with release build) if all of following conditions are met by specifically creating crafted account state and transaction by malicious users:
lamportsis identical assource.lamports().splitaccount is bigger than source; sosplit_rent_exempt_reserve>meta.rent_exempt_reservesplitaccount is pre-funded so thatsplit.lamports()? + lamports >= split_rent_exempt_reserve.
There was a problem hiding this comment.
I think the best thing we could here is to reject such a case? Also, I'd like to add a test for this. (I know you already adding very extensive set of tests. Sorry for more trouble).
There was a problem hiding this comment.
I think I see. I'll write a test to confirm. Yes, I think rejecting makes sense.
There was a problem hiding this comment.
Please see test_split_100_percent_of_source_to_larger_account_edge_case()
| // requested, less any lamports needed to cover the rent-exempt reserve | ||
| ( | ||
| lamports, | ||
| lamports - split_rent_exempt_reserve.saturating_sub(split.lamports()?), |
There was a problem hiding this comment.
I think similar attack is possible here like this: https://github.com/solana-labs/solana/pull/13357/files#r517344371
There was a problem hiding this comment.
This case is covered by the initial lamports check, more obvious with your rewriting:
lamports < split_rent_exempt_reserve.saturating_sub(split.lamports()?)
lamports must be greater than or equal to that value
There was a problem hiding this comment.
I included my test that demonstrates this: test_split_to_larger_account_edge_case()
|
Still pondering on this. But I think this getting very solid with many new tests. Thanks for great work! |
maybe, this fn: solana/sdk/program/src/rent.rs Line 49 in b0d1ae1 along like: |
t-nelson
left a comment
There was a problem hiding this comment.
Looking good! I just have a couple test hardening recommendations
|
This will need rebasing on #13394 (make sure it goes in stake_state.rs, as opposed to the legacy mod) |
4b344a1 to
12fa28f
Compare
Pull request has been modified.
…t overflow splits
12fa28f to
1ddc739
Compare
* Add failing tests * Fix stake split * Calculate split rent-exempt-reserve and use * Add comment in rent.rs * Add tests for edge cases when splitting to larger accounts, and reject overflow splits * Reframe InsufficientFunds checks in terms of lamports var * Test hardening review comments (cherry picked from commit 4c5f345)
* Add failing tests * Fix stake split * Calculate split rent-exempt-reserve and use * Add comment in rent.rs * Add tests for edge cases when splitting to larger accounts, and reject overflow splits * Reframe InsufficientFunds checks in terms of lamports var * Test hardening review comments (cherry picked from commit 4c5f345)
* Add failing tests * Fix stake split * Calculate split rent-exempt-reserve and use * Add comment in rent.rs * Add tests for edge cases when splitting to larger accounts, and reject overflow splits * Reframe InsufficientFunds checks in terms of lamports var * Test hardening review comments (cherry picked from commit 4c5f345) Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
* Add failing tests * Fix stake split * Calculate split rent-exempt-reserve and use * Add comment in rent.rs * Add tests for edge cases when splitting to larger accounts, and reject overflow splits * Reframe InsufficientFunds checks in terms of lamports var * Test hardening review comments (cherry picked from commit 4c5f345) Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Problem
Stake split doesn't properly handle the stake deduction from a Delegated original account when the new account has a balance less than the rent-exempt reserve. The original stake needs to be reduced by the entire balance transferred, except in the case of splitting the entire source stake, when it should simply be zeroed.
Stake split also errors on an attempt to split all of a source account to a new account that holds a balance. This is inconsistent with the behavior for a partial split, where an existing balance is acceptable and used to cover the rent-exempt reserve (see
test_split_with_rent()).Summary of Changes
Before/after examples added in comments.
This is WIP as I need to coordinate gating with @t-nelson
cc: @ryoqun @mvines