-
Notifications
You must be signed in to change notification settings - Fork 894
genesis: create EpochRewards at epoch 0 #6125
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
Conversation
74024a6 to
66624cc
Compare
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #6125 +/- ##
=========================================
- Coverage 82.8% 82.8% -0.1%
=========================================
Files 848 849 +1
Lines 378808 378817 +9
=========================================
- Hits 313796 313781 -15
- Misses 65012 65036 +24 🚀 New features to boost your workflow:
|
59dd499 to
7cadcb0
Compare
|
Backports to the beta branch are to be avoided unless absolutely necessary for fixing bugs, security issues, and perf regressions. Changes intended for backport should be structured such that a minimum effective diff can be committed separately from any refactoring, plumbing, cleanup, etc that are not strictly necessary to achieve the goal. Any of the latter should go only into master and ride the normal stabilization schedule. Exceptions include CI/metrics changes, CLI improvements and documentation updates on a case by case basis. |
runtime/src/genesis_utils.rs
Outdated
| let epoch_rewards_account = AccountSharedData::create( | ||
| 1, | ||
| vec![0; EpochRewards::size_of()], | ||
| sysvar::id(), | ||
| false, | ||
| u64::MAX, | ||
| ); | ||
| initial_accounts.push((epoch_rewards::id(), epoch_rewards_account)); |
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.
based on watching the account on solana-test-validator there is no reason to get clever with the lamports here because it gets reset to the rent-exempt minimum at the first epoch boundary anyway. we could hardcode the value 1454640 but i avoided getting it via rent.minimum_balance() because lamports_per_signature is 0 in some tests, so im wary using Rent during genesis is brittle
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 using rent during genesis when creating the stake config:
agave/programs/stake/src/config.rs
Lines 46 to 50 in b88655c
| pub fn add_genesis_account(genesis_config: &mut GenesisConfig) -> u64 { | |
| let mut account = create_config_account(vec![], &Config::default(), 0); | |
| let lamports = genesis_config.rent.minimum_balance(account.data().len()); | |
| account.set_lamports(lamports.max(1)); |
So let's do that here as well.
Also, is there a reason to add the new account here as opposed to here?
agave/programs/stake/src/lib.rs
Lines 16 to 18 in b88655c
| pub fn add_genesis_accounts(genesis_config: &mut GenesisConfig) -> u64 { | |
| config::add_genesis_account(genesis_config) | |
| } |
That way, totally new Solana networks using solana-genesis will also get the account:
Line 750 in b88655c
| solana_stake_program::add_genesis_accounts(&mut genesis_config); |
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 moved it to the stake program function, i didnt know there was a separate genesis cli that didnt use genesis utils
|
i tagged this to backport because it has no effect on runtime behavior for any cluster (so it is safe), the only impact is to make the 2.2 version of |
joncinque
left a comment
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.
Just a comment about where to put the function, the logic looks good!
runtime/src/genesis_utils.rs
Outdated
| let epoch_rewards_account = AccountSharedData::create( | ||
| 1, | ||
| vec![0; EpochRewards::size_of()], | ||
| sysvar::id(), | ||
| false, | ||
| u64::MAX, | ||
| ); | ||
| initial_accounts.push((epoch_rewards::id(), epoch_rewards_account)); |
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 using rent during genesis when creating the stake config:
agave/programs/stake/src/config.rs
Lines 46 to 50 in b88655c
| pub fn add_genesis_account(genesis_config: &mut GenesisConfig) -> u64 { | |
| let mut account = create_config_account(vec![], &Config::default(), 0); | |
| let lamports = genesis_config.rent.minimum_balance(account.data().len()); | |
| account.set_lamports(lamports.max(1)); |
So let's do that here as well.
Also, is there a reason to add the new account here as opposed to here?
agave/programs/stake/src/lib.rs
Lines 16 to 18 in b88655c
| pub fn add_genesis_accounts(genesis_config: &mut GenesisConfig) -> u64 { | |
| config::add_genesis_account(genesis_config) | |
| } |
That way, totally new Solana networks using solana-genesis will also get the account:
Line 750 in b88655c
| solana_stake_program::add_genesis_accounts(&mut genesis_config); |
| if slot == SLOTS_PER_EPOCH { | ||
| // cap should increase because of new epoch rewards | ||
| assert!(post_cap > pre_cap); | ||
| } else { | ||
| assert_eq!(post_cap, pre_cap); | ||
| } |
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.
Very nice! It's great to get rid of these hacks
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 like it.
|
The Firedancer team maintains a line-for-line reimplementation of the |
1711da1 to
c37b620
Compare
c37b620 to
05a6cc4
Compare
| genesis_config | ||
| .accounts | ||
| .get_mut(&epoch_rewards::id()) | ||
| .unwrap() | ||
| .set_lamports(1); |
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 seems fine to me to prevent EpochRewards from being immediately deallocated instead of adding back the slot == SLOTS_PER_EPOCH hack. these tests use Rent::free() because there are rent-paying accounts so using Rent::default() would mess up the capitalization() checks
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.
That makes sense to me. Can you just add a comment to explain the rationale since we'll probably forget?
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.
alright i understand everything now
test-validator uses create_genesis_config_with_leader_ex_no_features() directly with configured Rent (and its "no fees" variant is 1 lamport per byte-year rather than 0) so it creates a rent-exempt EpochRewards. the failing runtime test uses a create_genesis_config_with_leader_ex_no_features() wrapper with Rent::free() which sets 0 lamports per byte-year just like the partitioned epoch rewards tests, so EpochRewards is created with 0 lamports. then that test compares the total bytes allocated to the total bytes of all loadable accounts and gets a mismatch because EpochRewards still exists and is not garbage-collected (because there is no rent) but does not "exist" from the point of view of get_account() (because it has zero lamports)
instead of test hacks i realized i could just create EpochRewards with the max of rent exemption and 1, made this change, then rechecked StakeConfig because it should trigger this runtime test too... and i had failed to notice account.set_lamports(lamports.max(1)); which is subtly wrong because it returns the wrong value, but nothing checks it
tldr it is just test setup but there is an easy fix with prior art that requires no hacks
joncinque
left a comment
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 good to me, just needs a little comment on the test change
| genesis_config | ||
| .accounts | ||
| .get_mut(&epoch_rewards::id()) | ||
| .unwrap() | ||
| .set_lamports(1); |
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.
That makes sense to me. Can you just add a comment to explain the rationale since we'll probably forget?
|
Also, test failure looks legit |
joncinque
left a comment
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.
Ah right, I missed that too 😞 but this looks good to me!
(cherry picked from commit 8aaa0c7) # Conflicts: # programs/stake/src/lib.rs # runtime/src/bank/partitioned_epoch_rewards/mod.rs
(cherry picked from commit 8aaa0c7)
(cherry picked from commit 8aaa0c7)
Problem
the bpf stake program depends on the existence of
EpochRewardsto function, but this account does not exist until epoch 1. this means:solana-test-validatorin the first epochSummary of Changes
create a blank
SysvarEpochRewards1111111111111111111111111account at genesiscloses #4928