Skip to content
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

Stop loading program accounts if program exists in cache #30703

Merged
merged 20 commits into from
Mar 28, 2023

Conversation

pgarg66
Copy link
Contributor

@pgarg66 pgarg66 commented Mar 14, 2023

Problem

Program/ProgramData accounts get loaded even though the compiled program exists in the cache.

Summary of Changes

Check if the compiled program is already cached. If it is, do not load its program and program data accounts.

Fixes #

@pgarg66 pgarg66 requested a review from Lichtso March 14, 2023 05:18
@pgarg66 pgarg66 force-pushed the cache-try branch 2 times, most recently from 9cd3eab to 538acbe Compare March 15, 2023 13:17
@codecov
Copy link

codecov bot commented Mar 17, 2023

Codecov Report

Merging #30703 (df0bd1d) into master (49b8ea7) will decrease coverage by 0.1%.
The diff coverage is 76.9%.

@@            Coverage Diff            @@
##           master   #30703     +/-   ##
=========================================
- Coverage    81.5%    81.5%   -0.1%     
=========================================
  Files         727      727             
  Lines      205150   205178     +28     
=========================================
+ Hits       167273   167280      +7     
- Misses      37877    37898     +21     

@pgarg66 pgarg66 marked this pull request as ready for review March 18, 2023 16:50
@pgarg66 pgarg66 force-pushed the cache-try branch 2 times, most recently from 3308e3c to f3b5c26 Compare March 20, 2023 20:46
sanitized_txs: &[SanitizedTransaction],
check_results: &mut [TransactionCheckResult],
) -> (
HashMap<Pubkey, &'a Pubkey>,
HashMap<Pubkey, Arc<LoadedProgram>>,
) {
let mut filter_programs_time = Measure::start("filter_programs_accounts");
let program_accounts_map = self.rc.accounts.filter_executable_program_accounts(
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be factored out to call site, so that we don't need to return program_accounts_map, but that can be done in a separate PR.

@@ -180,9 +180,6 @@ pub fn load_program_from_account(
return Err(InstructionError::IncorrectProgramId);
}

let (programdata_offset, deployment_slot) =
get_programdata_offset_and_depoyment_offset(&log_collector, program, programdata)?;

if let Some(ref tx_executor_cache) = tx_executor_cache {
if let Some(loaded_program) = tx_executor_cache.get(program.get_key()) {
if loaded_program.is_tombstone() {
Copy link
Contributor

Choose a reason for hiding this comment

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

We can have tombstone in the TX batch cache now, even if delay_visibility_of_program_deployment is not enabled, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, in case the program fails to compile/verify.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was referring to the comment below which is incorrect now.

@@ -180,9 +180,6 @@ pub fn load_program_from_account(
return Err(InstructionError::IncorrectProgramId);
}

let (programdata_offset, deployment_slot) =
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this code movement necessary?
Bit concerned about error priorities here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, since we don't load the actual program account, the get_programdata_offset_and_depoyment_offset returns an error, since state() is not valid.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looking through the code, get_programdata_offset_and_depoyment_offset() returns InvalidAccountData in all error scenarios. So, moving the code after cache lookup should not change the error codes (as the cache lookup failure returns the same error code).

.get_number_of_program_accounts()
.saturating_sub(2),
)
.ok()
Copy link
Contributor

Choose a reason for hiding this comment

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

As this is only an Option type this could lead to a confusion between the upgradeable loader vs the normal loader and whether a program was loaded in a transaction or not (e.g. used for an instruction or has the is_writable flag in the message).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

load_program_from_account() call preceding this code block is always going to return the program entry from the cache. This code block will be deleted in the follow up PR, and replaced with the cache lookup.

Would you prefer if the code deletion/refactor was done in this PR itself. It was causing some changes to tests in other parts of the code which are unrelated to this PR.

) -> Result<AccountSharedData> {
// Check for tombstone
if program.is_tombstone() {
return Err(TransactionError::InvalidProgramForExecution);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this changes the error code for attempting to execute a closed program.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll check and fix it.

Copy link
Contributor Author

@pgarg66 pgarg66 Mar 21, 2023

Choose a reason for hiding this comment

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

We probably need to store the reason for tombstone in the cache. Otherwise we don't have enough information to return the correct error code.

runtime/src/accounts.rs Outdated Show resolved Hide resolved
program-runtime/src/loaded_programs.rs Outdated Show resolved Hide resolved
program-runtime/src/loaded_programs.rs Outdated Show resolved Hide resolved
@@ -180,9 +180,6 @@ pub fn load_program_from_account(
return Err(InstructionError::IncorrectProgramId);
}

let (programdata_offset, deployment_slot) =
get_programdata_offset_and_depoyment_offset(&log_collector, program, programdata)?;

if let Some(ref tx_executor_cache) = tx_executor_cache {
if let Some(loaded_program) = tx_executor_cache.get(program.get_key()) {
if loaded_program.is_tombstone() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I was referring to the comment below which is incorrect now.

runtime/src/accounts.rs Outdated Show resolved Hide resolved
@pgarg66
Copy link
Contributor Author

pgarg66 commented Mar 28, 2023

Tested by cherry-picking #30928 on top of this PR. The results match for all the modified tests.

@pgarg66 pgarg66 requested a review from Lichtso March 28, 2023 13:17
@pgarg66 pgarg66 requested a review from Lichtso March 28, 2023 16:56
@pgarg66 pgarg66 merged commit aebc191 into solana-labs:master Mar 28, 2023
@pgarg66 pgarg66 deleted the cache-try branch March 28, 2023 18:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

Successfully merging this pull request may close these issues.

2 participants