-
Notifications
You must be signed in to change notification settings - Fork 4.5k
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
Refactor: Replaces KeyedAccount
by BorrowedAccount
in BPF loaders
#23056
Refactor: Replaces KeyedAccount
by BorrowedAccount
in BPF loaders
#23056
Conversation
9d8c9c0
to
3da0beb
Compare
Codecov Report
@@ Coverage Diff @@
## master #23056 +/- ##
=========================================
- Coverage 81.3% 81.3% -0.1%
=========================================
Files 572 572
Lines 155876 156213 +337
=========================================
+ Hits 126815 127086 +271
- Misses 29061 29127 +66 |
59b9fe2
to
4e09fc7
Compare
bd6a5d4
to
08e032f
Compare
} | ||
UpgradeableLoaderInstruction::Write { offset, bytes } => { | ||
let buffer = keyed_account_at_index(keyed_accounts, first_instruction_account)?; | ||
let authority = keyed_account_at_index(keyed_accounts, first_instruction_account + 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 is probably an error order mismatch, we used to check the authority account was present up front, but now check it much later after other checks
programs/bpf_loader/src/lib.rs
Outdated
if authority_address != upgrade_authority_address { | ||
ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match"); | ||
return Err(InstructionError::IncorrectAuthority); | ||
} | ||
if upgrade_authority_signer { | ||
if !instruction_context.is_signer(first_instruction_account + 7)? { |
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 is another case where the account being present was checked much earlier before. There are probably other cases in this function
let keyed_accounts = invoke_context.get_keyed_accounts()?; | ||
let instruction = limited_deserialize(instruction_data)?; | ||
|
||
trace!("process_instruction: {:?}", instruction); | ||
trace!("keyed_accounts: {:?}", keyed_accounts); | ||
|
||
let _ = keyed_account_at_index(keyed_accounts, first_instruction_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.
Checking first account is now gone, that's a behavior change
This is a good step in the right direction but a doozy of a PR. I found a few of what looks like un-featurized behavior changes and I'm pretty sure there are a lot more. Might be easier to break this up into smaller changes to help review. |
Thanks @jackcmay ! The error order mismatches are already on my radar and unfortunately we don't have tests for them. About the magic numbers, would going for enums or constants with the instruction account indices be better? If so, which do you prefer? |
Would be cool if the account indexes could be derived from the instruction comments so we have a single source of authority. We could use an enum per instruction and have the instruction documentation refer to those enums rather than repeat the info. In the short term something local to the program would be ok and consts seems like the better choice but either one is fine. As long as we have some way to cleaning up the |
5ecb141
to
449ecc4
Compare
449ecc4
to
c583fa0
Compare
c583fa0
to
757d833
Compare
let buffer = keyed_account_at_index(keyed_accounts, first_instruction_account + 3)?; | ||
let rent = get_sysvar_with_account_check::rent( | ||
keyed_account_at_index(keyed_accounts, first_instruction_account + 4)?, | ||
instruction_context.check_number_of_instruction_accounts(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.
Why isn't thius 5?
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.
You are right, but it should be 4 I think, because the sysvar checks its own presence in get_sysvar_with_account_check2()
.
let buffer = keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?; | ||
let rent = get_sysvar_with_account_check::rent( | ||
keyed_account_at_index(keyed_accounts, first_instruction_account + 4)?, | ||
instruction_context.check_number_of_instruction_accounts(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.
4?
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.
Again, you are right but it should be 3.
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.
4 seems clearer since that is the number of accounts we expect
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 don't want to mix the "normal" parameters and sysvars as we might disable sysvars being passed as accounts using a feature gate.
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.
Its more clear to include all the accounts especially since the sysvars might not always be last. If we change it the feature gate should include the change in the number of accounts expected
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.
Its more clear to include all the accounts especially since the sysvars might not always be last
Exactly, and combined with the answer to why check_number_of_instruction_accounts
is called twice this is the reason not to include them. Currently we have to do a separate check for every consecutive run of "normal" accounts until it is interrupted by a sysvar. But once we feaure gate the sysvar account check, we can merge all these check_number_of_instruction_accounts
into one which covers all account indices at once.
ic_logger_msg!(log_collector, "ProgramData account not large enough"); | ||
return Err(InstructionError::AccountDataTooSmall); | ||
} | ||
if programdata.lamports()? + buffer.lamports()? < programdata_balance_required { | ||
if programdata.get_lamports() + buffer.get_lamports() < programdata_balance_required { |
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.
Be helpful if these name changes came in a different PR (before) to reduce the noise when trying to review and find order/behavior differences.
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 is not a rename of methods, it uses BorrowedAccount
instead of KeyedAccount
now.
The ?
at the end of each is gone as well.
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.
Was thinking that borrowed account exportlamports()
and then once all the rework is complete switch the name over. That way the reworking of accounts/error order is easier to grok in this pr
ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match"); | ||
return Err(InstructionError::IncorrectAuthority); | ||
} | ||
if authority.signer_key().is_none() { | ||
if !instruction_context.is_signer( |
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 difference in index base here can lead to confusion
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.
True and already on my TODO list of things to iron out once I refactored all builtin programs.
Did not want to bring that change into this PR as well.
.map(|account| account.unsigned_key()); | ||
|
||
match account.state()? { | ||
instruction_context.check_number_of_instruction_accounts(2)?; |
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.
3?
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 2, because NewAuthority
is optional.
KeyedAccount
KeyedAccount
by BorrowedAccount
in BPF loaders
let authority = keyed_account_at_index(keyed_accounts, first_instruction_account + 7)?; | ||
let upgrade_authority_address = Some(*authority.unsigned_key()); | ||
let upgrade_authority_signer = authority.signer_key().is_none(); | ||
instruction_context.check_number_of_instruction_accounts(8)?; |
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.
Why call this twice and shouldn't it be 7?
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 was: let authority = keyed_account_at_index(keyed_accounts, first_instruction_account + 7)?
So 8 slots total, no optional ones.
And it is called twice when sysvars are mixed in between as they can throw a different error.
* Revert "Replaces KeyedAccount by BorrowedAccount in the BPF loader. (#23056)" 6c56eb9 * Revert "Replaces `KeyedAccount` by `BorrowedAccount` in `system_instruction_processor`. (#23217)" ee7e411 * Revert "Replaces `KeyedAccount` by `BorrowedAccount` in `nonce_keyed_account`. (#23214)" 1a68f81 * Revert "Replaces KeyedAccount by BorrowedAccount in the config processor. (#23302)" a14c7c3 * Revert "Replaces `KeyedAccount` by `BorrowedAccount` in vote processor (#23348)" e2fa6a0 * Revert "Refactor: Prepare stake_instruction.rs to remove `KeyedAccount`s (#23375)" ee3fc39
Problem
There are use sites of
KeyedAccount
remaining in the BPF loader and the built-in programs.Summary of Changes
Replaces
KeyedAccount
byBorrowedAccount
.Fixes #