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

Commit a1bbfe9

Browse files
committed
Fix builtin handling on epoch boundaries
1 parent ebe3d2d commit a1bbfe9

File tree

5 files changed

+72
-19
lines changed

5 files changed

+72
-19
lines changed

runtime/src/bank.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3198,6 +3198,11 @@ impl Bank {
31983198

31993199
/// Add a precompiled program account
32003200
pub fn add_precompiled_account(&self, program_id: &Pubkey) {
3201+
self.add_precompiled_account_with_owner(program_id, native_loader::id())
3202+
}
3203+
3204+
// Used by tests to simulate clusters with precompiles that aren't owned by the native loader
3205+
fn add_precompiled_account_with_owner(&self, program_id: &Pubkey, owner: Pubkey) {
32013206
if let Some(account) = self.get_account_with_fixed_root(program_id) {
32023207
if account.executable() {
32033208
// The account is already executable, that's all we need
@@ -3219,7 +3224,7 @@ impl Bank {
32193224
let (lamports, rent_epoch) = self.inherit_specially_retained_account_fields(&None);
32203225
let account = AccountSharedData::from(Account {
32213226
lamports,
3222-
owner: native_loader::id(),
3227+
owner,
32233228
data: vec![],
32243229
executable: true,
32253230
rent_epoch,
@@ -6494,12 +6499,12 @@ impl Bank {
64946499

64956500
fn apply_builtin_program_feature_transitions(
64966501
&mut self,
6497-
apply_transitions_for_new_features: bool,
6502+
only_apply_transitions_for_new_features: bool,
64986503
new_feature_activations: &HashSet<Pubkey>,
64996504
) {
65006505
let feature_set = self.feature_set.clone();
6501-
let should_apply_action_for_feature = |feature_id: &Pubkey| -> bool {
6502-
if apply_transitions_for_new_features {
6506+
let should_apply_action_for_feature_transition = |feature_id: &Pubkey| -> bool {
6507+
if only_apply_transitions_for_new_features {
65036508
new_feature_activations.contains(feature_id)
65046509
} else {
65056510
feature_set.is_active(feature_id)
@@ -6508,7 +6513,9 @@ impl Bank {
65086513

65096514
let builtin_feature_transitions = self.builtin_feature_transitions.clone();
65106515
for transition in builtin_feature_transitions.iter() {
6511-
if let Some(builtin_action) = transition.to_action(&should_apply_action_for_feature) {
6516+
if let Some(builtin_action) =
6517+
transition.to_action(&should_apply_action_for_feature_transition)
6518+
{
65126519
match builtin_action {
65136520
BuiltinAction::Add(builtin) => self.add_builtin(
65146521
&builtin.name,
@@ -13000,25 +13007,25 @@ pub(crate) mod tests {
1300013007
if bank.slot == 0 {
1300113008
assert_eq!(
1300213009
bank.hash().to_string(),
13003-
"HREoNvUAuqqGdJxYTgnFqjTxsuuBVUFFDNLGR2cdrtMf"
13010+
"9tLrxkBoNE7zEUZ2g72ZwE4fTfhUQnhC8A4Xt4EmYhP1"
1300413011
);
1300513012
}
1300613013
if bank.slot == 32 {
1300713014
assert_eq!(
1300813015
bank.hash().to_string(),
13009-
"J8kjxLMMrpEVQUbX54zDALkXidjdXyFSL5wD2d7xUaWL"
13016+
"7qCbZN5WLT928VpsaLwLp6HfRDzZirmoU4JM4XBEyupu"
1301013017
);
1301113018
}
1301213019
if bank.slot == 64 {
1301313020
assert_eq!(
1301413021
bank.hash().to_string(),
13015-
"yPCTEPtNi2DJb8KyqPKgBK7HCfiEpH2oS3Nn12LPBHm"
13022+
"D3ypfQFreDaQhJuuYN8rWG1TVy9ApvTCx5CAiQ5i9d7A"
1301613023
);
1301713024
}
1301813025
if bank.slot == 128 {
1301913026
assert_eq!(
1302013027
bank.hash().to_string(),
13021-
"2oG1rmA59tmr457oK4oF6C6TcM2gyy2ZAKeJoUhMNb1L"
13028+
"67krqDMqjkkixdfypnCCgSyUm2FoqAE8KB1hgRAtCaBp"
1302213029
);
1302313030
break;
1302413031
}
@@ -13247,7 +13254,7 @@ pub(crate) mod tests {
1324713254
// No more slots should be shrunk
1324813255
assert_eq!(bank2.shrink_candidate_slots(), 0);
1324913256
// alive_counts represents the count of alive accounts in the three slots 0,1,2
13250-
assert_eq!(alive_counts, vec![11, 1, 7]);
13257+
assert_eq!(alive_counts, vec![9, 1, 7]);
1325113258
}
1325213259

1325313260
#[test]
@@ -13295,7 +13302,7 @@ pub(crate) mod tests {
1329513302
.map(|_| bank.process_stale_slot_with_budget(0, force_to_return_alive_account))
1329613303
.sum();
1329713304
// consumed_budgets represents the count of alive accounts in the three slots 0,1,2
13298-
assert_eq!(consumed_budgets, 12);
13305+
assert_eq!(consumed_budgets, 10);
1329913306
}
1330013307

1330113308
#[test]

runtime/src/bank/builtin_programs.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,41 @@ mod tests {
55
solana_sdk::{feature_set::FeatureSet, genesis_config::create_genesis_config},
66
};
77

8+
#[test]
9+
fn test_apply_builtin_program_feature_transitions_for_new_epoch() {
10+
let (genesis_config, _mint_keypair) = create_genesis_config(100_000);
11+
12+
let mut bank = Bank::new_for_tests(&genesis_config);
13+
bank.feature_set = Arc::new(FeatureSet::all_enabled());
14+
bank.finish_init(&genesis_config, None, false);
15+
16+
// Overwrite precompile accounts to simulate a cluster which already added precompiles.
17+
for precompile in get_precompiles() {
18+
bank.store_account(&precompile.program_id, &AccountSharedData::default());
19+
// Simulate cluster which added ed25519 precompile with a system program owner
20+
if precompile.program_id == ed25519_program::id() {
21+
bank.add_precompiled_account_with_owner(
22+
&precompile.program_id,
23+
solana_sdk::system_program::id(),
24+
);
25+
} else {
26+
bank.add_precompiled_account(&precompile.program_id);
27+
}
28+
}
29+
30+
// Normally feature transitions are applied to a bank that hasn't been
31+
// frozen yet. Freeze the bank early to ensure that no account changes
32+
// are made.
33+
bank.freeze();
34+
35+
// Simulate crossing an epoch boundary for a new bank
36+
let only_apply_transitions_for_new_features = true;
37+
bank.apply_builtin_program_feature_transitions(
38+
only_apply_transitions_for_new_features,
39+
&HashSet::new(),
40+
);
41+
}
42+
843
#[test]
944
fn test_startup_from_snapshot_after_precompile_transition() {
1045
let (genesis_config, _mint_keypair) = create_genesis_config(100_000);

runtime/src/builtins.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ pub enum BuiltinFeatureTransition {
117117
/// Remove a builtin program if a feature is activated or
118118
/// retain a previously added builtin.
119119
RemoveOrRetain {
120-
previous_builtin: Builtin,
120+
previously_added_builtin: Builtin,
121+
addition_feature_id: Pubkey,
121122
removal_feature_id: Pubkey,
122123
},
123124
}
@@ -139,14 +140,17 @@ impl BuiltinFeatureTransition {
139140
}
140141
}
141142
Self::RemoveOrRetain {
142-
previous_builtin,
143+
previously_added_builtin,
144+
addition_feature_id,
143145
removal_feature_id,
144146
} => {
145147
if should_apply_action_for_feature(removal_feature_id) {
146-
Some(BuiltinAction::Remove(previous_builtin.id))
147-
} else {
148+
Some(BuiltinAction::Remove(previously_added_builtin.id))
149+
} else if should_apply_action_for_feature(addition_feature_id) {
148150
// Retaining is no different from adding a new builtin.
149-
Some(BuiltinAction::Add(previous_builtin.clone()))
151+
Some(BuiltinAction::Add(previously_added_builtin.clone()))
152+
} else {
153+
None
150154
}
151155
}
152156
}
@@ -200,19 +204,21 @@ fn builtin_feature_transitions() -> Vec<BuiltinFeatureTransition> {
200204
feature_id: feature_set::add_compute_budget_program::id(),
201205
},
202206
BuiltinFeatureTransition::RemoveOrRetain {
203-
previous_builtin: Builtin::new(
207+
previously_added_builtin: Builtin::new(
204208
"secp256k1_program",
205209
solana_sdk::secp256k1_program::id(),
206210
dummy_process_instruction,
207211
),
212+
addition_feature_id: feature_set::secp256k1_program_enabled::id(),
208213
removal_feature_id: feature_set::prevent_calling_precompiles_as_programs::id(),
209214
},
210215
BuiltinFeatureTransition::RemoveOrRetain {
211-
previous_builtin: Builtin::new(
216+
previously_added_builtin: Builtin::new(
212217
"ed25519_program",
213218
solana_sdk::ed25519_program::id(),
214219
dummy_process_instruction,
215220
),
221+
addition_feature_id: feature_set::ed25519_program_enabled::id(),
216222
removal_feature_id: feature_set::prevent_calling_precompiles_as_programs::id(),
217223
},
218224
BuiltinFeatureTransition::Add {

runtime/src/genesis_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub fn bootstrap_validator_stake_lamports() -> u64 {
2626

2727
// Number of lamports automatically used for genesis accounts
2828
pub const fn genesis_sysvar_and_builtin_program_lamports() -> u64 {
29-
const NUM_BUILTIN_PROGRAMS: u64 = 6;
29+
const NUM_BUILTIN_PROGRAMS: u64 = 4;
3030
const FEES_SYSVAR_MIN_BALANCE: u64 = 946_560;
3131
const STAKE_HISTORY_MIN_BALANCE: u64 = 114_979_200;
3232
const CLOCK_SYSVAR_MIN_BALANCE: u64 = 1_169_280;

sdk/src/feature_set.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ pub mod full_inflation {
5353
}
5454
}
5555

56+
pub mod secp256k1_program_enabled {
57+
solana_sdk::declare_id!("E3PHP7w8kB7np3CTQ1qQ2tW3KCtjRSXBQgW9vM2mWv2Y");
58+
}
59+
5660
pub mod spl_token_v2_multisig_fix {
5761
solana_sdk::declare_id!("E5JiFDQCwyC6QfT9REFyMpfK2mHcmv1GUDySU1Ue7TYv");
5862
}
@@ -314,6 +318,7 @@ pub mod record_instruction_in_transaction_context_push {
314318
lazy_static! {
315319
/// Map of feature identifiers to user-visible description
316320
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
321+
(secp256k1_program_enabled::id(), "secp256k1 program"),
317322
(deprecate_rewards_sysvar::id(), "deprecate unused rewards sysvar"),
318323
(pico_inflation::id(), "pico inflation"),
319324
(full_inflation::devnet_and_testnet::id(), "full inflation on devnet and testnet"),

0 commit comments

Comments
 (0)