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

Fix stake split rent-exempt adjustment#13357

Merged
mergify[bot] merged 7 commits intosolana-labs:masterfrom
CriesofCarrots:stake-split-bug
Nov 6, 2020
Merged

Fix stake split rent-exempt adjustment#13357
mergify[bot] merged 7 commits intosolana-labs:masterfrom
CriesofCarrots:stake-split-bug

Conversation

@CriesofCarrots
Copy link
Copy Markdown
Contributor

@CriesofCarrots CriesofCarrots commented Nov 3, 2020

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 (seetest_split_with_rent()).

Summary of Changes

  • Fix math

Before/after examples added in comments.

This is WIP as I need to coordinate gating with @t-nelson
cc: @ryoqun @mvines

@CriesofCarrots
Copy link
Copy Markdown
Contributor Author

CriesofCarrots commented Nov 3, 2020

Splitting partial amount into empty account (default cli behavior)

Before:

$ solana stake-account stake.json
Balance: 0.1 SOL
Rent Exempt Reserve: 0.00228288 SOL
Delegated Stake: 0.09771712 SOL
Active Stake: 0.09771712 SOL
Delegated Vote Account Address: 2FPim6EJBTW3uwr36fAhK8BEGB22BjJuxkPbtMYAeVUv

$ solana split-stake stake.json split.json 0.05
Signature: 4u1xhY2NqvsoGQHqh65QvJpT3AVyBoyv2K7Bx6h3JbuJ8NLwMFAeHKCZdhSi8wNm5huYMvmphqHn1nYzs39SLYRw

$ solana stake-account stake.json
Balance: 0.05 SOL
Rent Exempt Reserve: 0.00228288 SOL
Delegated Stake: 0.05 SOL <--- Notice stake is not less the rent-exempt-reserve
Active Stake: 0.05 SOL
Delegated Vote Account Address: 2FPim6EJBTW3uwr36fAhK8BEGB22BjJuxkPbtMYAeVUv

$ solana stake-account split.json`
Balance: 0.05 SOL
Rent Exempt Reserve: 0.00228288 SOL
Delegated Stake: 0.04771712 SOL
Active Stake: 0.04771712 SOL
Delegated Vote Account Address: 2FPim6EJBTW3uwr36fAhK8BEGB22BjJuxkPbtMYAeVUv

After:

$ solana stake-account stake.json
Balance: 0.1 SOL
Rent Exempt Reserve: 0.00228288 SOL
Delegated Stake: 0.09771712 SOL
Active Stake: 0.09771712 SOL
Delegated Vote Account Address: GGohSWd9vwLDqfu32nXuzYM7B6W8N7baRSo5ph9CJsG9

$ solana split-stake stake.json split.json 0.05
Signature: 4oEubJWX4WcjDQaN2KtN2Li4TsZD3WRDeWfGGAg26FzWATKEbJt8Nc84zhfMDx78pY1oxgnGhQMsWDhB75MJTTSK

$ solana stake-account stake.json
Balance: 0.05 SOL
Rent Exempt Reserve: 0.00228288 SOL
Delegated Stake: 0.04771712 SOL
Active Stake: 0.04771712 SOL
Delegated Vote Account Address: GGohSWd9vwLDqfu32nXuzYM7B6W8N7baRSo5ph9CJsG9

$ solana stake-account split.json
Balance: 0.05 SOL
Rent Exempt Reserve: 0.00228288 SOL
Delegated Stake: 0.04771712 SOL
Active Stake: 0.04771712 SOL
Delegated Vote Account Address: GGohSWd9vwLDqfu32nXuzYM7B6W8N7baRSo5ph9CJsG9

@CriesofCarrots
Copy link
Copy Markdown
Contributor Author

CriesofCarrots commented Nov 3, 2020

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):

system_instruction::create_account(
  authorized_pubkey, // Sending 0, so any signer will suffice
  split_stake_pubkey,
  2282880,
  std::mem::size_of::<StakeState>() as u64,
  &id(),
)

Before:

$ solana stake-account stake.json
Balance: 0.1 SOL
Rent Exempt Reserve: 0.00228288 SOL
Delegated Stake: 0.09771712 SOL
Active Stake: 0.09771712 SOL
Delegated Vote Account Address: JCcavabWfWZc9ykWb68Vjvpy6oH6nYWGrkwFdEnk4Z95

$ solana split-stake stake.json split.json 0.1
Error: RPC response error -32002: Transaction simulation failed: Error processing Instruction 1: custom program error: 0x4

After:

$ solana stake-account /Users/tyeraeulberg/.config/solana/stake.json`
Balance: 0.1 SOL
Rent Exempt Reserve: 0.00228288 SOL
Delegated Stake: 0.09771712 SOL
Active Stake: 0.09771712 SOL
Delegated Vote Account Address: FmM9tLoFrqAAS6K9MrMxDWT2o1RzpE5cv388iYJSMAm2
Stake Authority: Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX
Withdraw Authority: Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX

$ solana split-stake stake.json split.json 0.1
Signature: rVtvcTHJX6VYdYBPKyiX9rssVAB9SUSK6jNU28HSmwTMf9HJXVsrKRtrSCfVjbeam8V34CNFR8BmkDwkNPRHFVq

$ solana stake-account stake.json
Error: AccountNotFound: pubkey=CYRJWqiSjLitBAcRxPvWpgX3s5TvmN2SuRY3eEYypFvT

$ solana stake-account split.json
Balance: 0.10228288 SOL
Rent Exempt Reserve: 0.00228288 SOL
Delegated Stake: 0.09771712 SOL
Active Stake: 0.09771712 SOL
Delegated Vote Account Address: FmM9tLoFrqAAS6K9MrMxDWT2o1RzpE5cv388iYJSMAm2

@CriesofCarrots
Copy link
Copy Markdown
Contributor Author

@rwalker-com , would you be able to take a look at this and see if I'm missing anything? 🙏

@CriesofCarrots CriesofCarrots added the work in progress This isn't quite right yet label Nov 3, 2020
@CriesofCarrots CriesofCarrots marked this pull request as ready for review November 3, 2020 02:20
Copy link
Copy Markdown
Contributor

@rwalker-com rwalker-com left a comment

Choose a reason for hiding this comment

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

lgtm. all I had to do was read tests :-)

@codecov
Copy link
Copy Markdown

codecov Bot commented Nov 3, 2020

Codecov Report

Merging #13357 (12fa28f) into master (fe1e08b) will increase coverage by 0.0%.
The diff coverage is 99.6%.

@@           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 t-nelson mentioned this pull request Nov 3, 2020
t-nelson
t-nelson previously approved these changes Nov 3, 2020
Copy link
Copy Markdown
Contributor

@t-nelson t-nelson left a comment

Choose a reason for hiding this comment

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

LGTM! Just a couple comment typoes

Comment thread programs/stake/src/stake_state.rs Outdated
Comment thread programs/stake/src/stake_state.rs Outdated
@mergify mergify Bot dismissed t-nelson’s stale review November 3, 2020 04:51

Pull request has been modified.

Comment thread programs/stake/src/stake_state.rs Outdated
Comment thread programs/stake/src/stake_state.rs Outdated
Comment thread programs/stake/src/stake_state.rs
Comment thread programs/stake/src/stake_state.rs
Comment on lines +1016 to +1023
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)
Copy link
Copy Markdown
Contributor

@ryoqun ryoqun Nov 3, 2020

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Where would you like to see that comment in rent.rs?

Comment thread programs/stake/src/stake_state.rs Outdated
Comment thread programs/stake/src/stake_state.rs Outdated
Comment thread programs/stake/src/stake_state.rs Outdated
Comment thread programs/stake/src/stake_state.rs Outdated
Comment thread programs/stake/src/stake_state.rs Outdated
// split account.
(
lamports - meta.rent_exempt_reserve,
lamports - split_rent_exempt_reserve,
Copy link
Copy Markdown
Contributor

@ryoqun ryoqun Nov 4, 2020

Choose a reason for hiding this comment

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

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:

  1. lamports is identical as source.lamports().
  2. split account is bigger than source; so split_rent_exempt_reserve > meta.rent_exempt_reserve
  3. split account is pre-funded so that split.lamports()? + lamports >= split_rent_exempt_reserve.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think I see. I'll write a test to confirm. Yes, I think rejecting makes sense.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Please see test_split_100_percent_of_source_to_larger_account_edge_case()

Comment thread programs/stake/src/stake_state.rs Outdated
// requested, less any lamports needed to cover the rent-exempt reserve
(
lamports,
lamports - split_rent_exempt_reserve.saturating_sub(split.lamports()?),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

@CriesofCarrots CriesofCarrots Nov 4, 2020

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I included my test that demonstrates this: test_split_to_larger_account_edge_case()

@ryoqun
Copy link
Copy Markdown
Contributor

ryoqun commented Nov 4, 2020

Still pondering on this. But I think this getting very solid with many new tests. Thanks for great work!

@ryoqun
Copy link
Copy Markdown
Contributor

ryoqun commented Nov 4, 2020

@ryoqun , hoping for a little more guidance about where you'd like documentation in rent.rs bowing_woman . Otherwise, I think I've addressed all of your comments.

maybe, this fn:

pub fn minimum_balance(&self, data_len: usize) -> u64 {

along like:

// note that stripped down version of this calcuration is reluctantly copied into calculate_split_rent_exempt_reserve in the stake program

Copy link
Copy Markdown
Contributor

@t-nelson t-nelson left a comment

Choose a reason for hiding this comment

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

Looking good! I just have a couple test hardening recommendations

Comment thread programs/stake/src/stake_state.rs
Comment thread programs/stake/src/stake_state.rs Outdated
@CriesofCarrots
Copy link
Copy Markdown
Contributor Author

This will need rebasing on #13394 (make sure it goes in stake_state.rs, as opposed to the legacy mod)

t-nelson
t-nelson previously approved these changes Nov 4, 2020
Copy link
Copy Markdown
Contributor

@t-nelson t-nelson left a comment

Choose a reason for hiding this comment

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

LGTM!

@CriesofCarrots CriesofCarrots removed the work in progress This isn't quite right yet label Nov 6, 2020
@mergify mergify Bot dismissed t-nelson’s stale review November 6, 2020 12:56

Pull request has been modified.

@CriesofCarrots CriesofCarrots added the automerge Merge this Pull Request automatically once CI passes label Nov 6, 2020
@mergify mergify Bot merged commit 4c5f345 into solana-labs:master Nov 6, 2020
mergify Bot pushed a commit that referenced this pull request Nov 6, 2020
* 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)
mergify Bot pushed a commit that referenced this pull request Nov 6, 2020
* 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)
mergify Bot added a commit that referenced this pull request Nov 6, 2020
* 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>
mergify Bot added a commit that referenced this pull request Nov 6, 2020
* 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>
@CriesofCarrots CriesofCarrots deleted the stake-split-bug branch November 18, 2020 00:26
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

automerge Merge this Pull Request automatically once CI passes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants