From 9c6e7e0435fced43f5b1a864e08ea32ce5cb1c24 Mon Sep 17 00:00:00 2001 From: Pankaj Garg Date: Fri, 5 May 2023 06:08:57 -0700 Subject: [PATCH] Return implicit delay visibility tombstone (#31493) --- program-runtime/src/loaded_programs.rs | 59 +++++++++++++++++++++----- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/program-runtime/src/loaded_programs.rs b/program-runtime/src/loaded_programs.rs index 1b32d6dbce..001276db0c 100644 --- a/program-runtime/src/loaded_programs.rs +++ b/program-runtime/src/loaded_programs.rs @@ -25,6 +25,7 @@ use { }; const MAX_LOADED_ENTRY_COUNT: usize = 256; +const DELAY_VISIBILITY_SLOT_OFFSET: Slot = 1; /// Relationship between two fork IDs #[derive(Copy, Clone, PartialEq)] @@ -231,8 +232,8 @@ impl LoadedProgram { } pub fn new_tombstone(slot: Slot, reason: LoadedProgramType) -> Self { - let maybe_expiration_slot = - matches!(reason, LoadedProgramType::DelayVisibility).then_some(slot.saturating_add(1)); + let maybe_expiration_slot = matches!(reason, LoadedProgramType::DelayVisibility) + .then_some(slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET)); let tombstone = Self { program: reason, account_size: 0, @@ -429,6 +430,18 @@ impl LoadedPrograms { if current_slot >= entry.effective_slot { return Some((key, entry.clone())); + } else if entry.effective_slot.saturating_sub(entry.deployment_slot) + == DELAY_VISIBILITY_SLOT_OFFSET + && current_slot >= entry.deployment_slot + { + // Found a program entry on the current fork, but it's not effective + // yet. It indicates that the program has delayed visibility. Return + // the tombstone to reflect that. + let delay_visibility = LoadedProgram::new_tombstone( + entry.deployment_slot, + LoadedProgramType::DelayVisibility, + ); + return Some((key, Arc::new(delay_visibility))); } } } @@ -533,7 +546,7 @@ mod tests { use { crate::loaded_programs::{ BlockRelation, ForkGraph, LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType, - LoadedPrograms, LoadedProgramsForTxBatch, WorkingSlot, + LoadedPrograms, LoadedProgramsForTxBatch, WorkingSlot, DELAY_VISIBILITY_SLOT_OFFSET, }, percentage::Percentage, solana_rbpf::vm::BuiltInProgram, @@ -1100,7 +1113,14 @@ mod tests { let program2 = Pubkey::new_unique(); assert!(!cache.replenish(program2, new_test_loaded_program(5, 6)).0); - assert!(!cache.replenish(program2, new_test_loaded_program(11, 12)).0); + assert!( + !cache + .replenish( + program2, + new_test_loaded_program(11, 11 + DELAY_VISIBILITY_SLOT_OFFSET) + ) + .0 + ); let program3 = Pubkey::new_unique(); assert!(!cache.replenish(program3, new_test_loaded_program(25, 26)).0); @@ -1109,7 +1129,14 @@ mod tests { assert!(!cache.replenish(program4, new_test_loaded_program(0, 1)).0); assert!(!cache.replenish(program4, new_test_loaded_program(5, 6)).0); // The following is a special case, where effective slot is 3 slots in the future - assert!(!cache.replenish(program4, new_test_loaded_program(15, 18)).0); + assert!( + !cache + .replenish( + program4, + new_test_loaded_program(15, 15 + DELAY_VISIBILITY_SLOT_OFFSET) + ) + .0 + ); // Current fork graph // 0 @@ -1146,7 +1173,7 @@ mod tests { assert!(missing.contains(&program3)); // Testing fork 0 - 5 - 11 - 15 - 16 with current slot at 16 - let mut working_slot = TestWorkingSlot::new(16, &[0, 5, 11, 15, 16, 18, 19, 23]); + let mut working_slot = TestWorkingSlot::new(15, &[0, 5, 11, 15, 16, 18, 19, 23]); let (found, missing) = cache.extract( &working_slot, vec![ @@ -1158,11 +1185,17 @@ mod tests { .into_iter(), ); - assert!(match_slot(&found, &program1, 0, 16)); - assert!(match_slot(&found, &program2, 11, 16)); + assert!(match_slot(&found, &program1, 0, 15)); + assert!(match_slot(&found, &program2, 11, 15)); // The effective slot of program4 deployed in slot 15 is 19. So it should not be usable in slot 16. - assert!(match_slot(&found, &program4, 5, 16)); + // A delay visibility tombstone should be returned here. + let tombstone = found.find(program4).expect("Failed to find the tombstone"); + assert!(matches!( + tombstone.program, + LoadedProgramType::DelayVisibility + )); + assert_eq!(tombstone.deployment_slot, 15); assert!(missing.contains(&program3)); @@ -1222,7 +1255,13 @@ mod tests { ); assert!(match_slot(&found, &program1, 0, 11)); - assert!(match_slot(&found, &program2, 5, 11)); + // program2 was updated at slot 11, but is not effective till slot 12. The result should contain a tombstone. + let tombstone = found.find(program2).expect("Failed to find the tombstone"); + assert!(matches!( + tombstone.program, + LoadedProgramType::DelayVisibility + )); + assert_eq!(tombstone.deployment_slot, 11); assert!(match_slot(&found, &program4, 5, 11)); assert!(missing.contains(&program3));