|
|
@@ -4091,8 +4091,7 @@ impl Bank {
|
|
|
.unwrap_or(false)
|
|
|
};
|
|
|
if builtin.enable_feature_id.is_none() && !builtin_is_bpf(&builtin.program_id) {
|
|
|
- self.transaction_processor.add_builtin(
|
|
|
- self,
|
|
|
+ self.add_builtin(
|
|
|
builtin.program_id,
|
|
|
builtin.name,
|
|
|
ProgramCacheEntry::new_builtin(0, builtin.name.len(), builtin.entrypoint),
|
|
|
@@ -5085,8 +5084,7 @@ impl Bank {
|
|
|
program_id: Pubkey,
|
|
|
builtin_function: BuiltinFunctionWithContext,
|
|
|
) {
|
|
|
- self.transaction_processor.add_builtin(
|
|
|
- self,
|
|
|
+ self.add_builtin(
|
|
|
program_id,
|
|
|
"mockup",
|
|
|
ProgramCacheEntry::new_builtin(self.slot, 0, builtin_function),
|
|
|
@@ -5383,8 +5381,7 @@ impl Bank {
|
|
|
};
|
|
|
|
|
|
if should_enable_builtin_on_feature_transition {
|
|
|
- self.transaction_processor.add_builtin(
|
|
|
- self,
|
|
|
+ self.add_builtin(
|
|
|
builtin.program_id,
|
|
|
builtin.name,
|
|
|
ProgramCacheEntry::new_builtin(
|
|
|
@@ -5521,8 +5518,54 @@ impl Bank {
|
|
|
}
|
|
|
|
|
|
pub fn add_builtin(&self, program_id: Pubkey, name: &str, builtin: ProgramCacheEntry) {
|
|
|
- self.transaction_processor
|
|
|
- .add_builtin(self, program_id, name, builtin)
|
|
|
+ debug!("Adding program {name} under {program_id:?}");
|
|
|
+ self.add_builtin_account(name, &program_id);
|
|
|
+ self.transaction_processor.add_builtin(program_id, builtin);
|
|
|
+ debug!("Added program {name} under {program_id:?}");
|
|
|
+ }
|
|
|
+
|
|
|
+ // NOTE: must hold idempotent for the same set of arguments
|
|
|
+ /// Add a builtin program account
|
|
|
+ fn add_builtin_account(&self, name: &str, program_id: &Pubkey) {
|
|
|
+ let existing_genuine_program =
|
|
|
+ self.get_account_with_fixed_root(program_id)
|
|
|
+ .and_then(|account| {
|
|
|
+ // it's very unlikely to be squatted at program_id as non-system account because of burden to
|
|
|
+ // find victim's pubkey/hash. So, when account.owner is indeed native_loader's, it's
|
|
|
+ // safe to assume it's a genuine program.
|
|
|
+ if native_loader::check_id(account.owner()) {
|
|
|
+ Some(account)
|
|
|
+ } else {
|
|
|
+ // malicious account is pre-occupying at program_id
|
|
|
+ self.burn_and_purge_account(program_id, account);
|
|
|
+ None
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // introducing builtin program
|
|
|
+ if existing_genuine_program.is_some() {
|
|
|
+ // The existing account is sufficient
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ assert!(
|
|
|
+ !self.freeze_started(),
|
|
|
+ "Can't change frozen bank by adding not-existing new builtin program ({name}, \
|
|
|
+ {program_id}). Maybe, inconsistent program activation is detected on snapshot \
|
|
|
+ restore?"
|
|
|
+ );
|
|
|
+
|
|
|
+ // Add a bogus executable builtin account, which will be loaded and ignored.
|
|
|
+ let (lamports, rent_epoch) =
|
|
|
+ self.inherit_specially_retained_account_fields(&existing_genuine_program);
|
|
|
+ let account: AccountSharedData = AccountSharedData::from(Account {
|
|
|
+ lamports,
|
|
|
+ data: name.as_bytes().to_vec(),
|
|
|
+ owner: solana_sdk_ids::native_loader::id(),
|
|
|
+ executable: true,
|
|
|
+ rent_epoch,
|
|
|
+ });
|
|
|
+ self.store_account_and_update_capitalization(program_id, &account);
|
|
|
}
|
|
|
|
|
|
pub fn get_bank_hash_stats(&self) -> BankHashStats {
|
|
|
@@ -5586,50 +5629,6 @@ impl TransactionProcessingCallback for Bank {
|
|
|
.load_with_fixed_root(&self.ancestors, pubkey)
|
|
|
}
|
|
|
|
|
|
- // NOTE: must hold idempotent for the same set of arguments
|
|
|
- /// Add a builtin program account
|
|
|
- fn add_builtin_account(&self, name: &str, program_id: &Pubkey) {
|
|
|
- let existing_genuine_program =
|
|
|
- self.get_account_with_fixed_root(program_id)
|
|
|
- .and_then(|account| {
|
|
|
- // it's very unlikely to be squatted at program_id as non-system account because of burden to
|
|
|
- // find victim's pubkey/hash. So, when account.owner is indeed native_loader's, it's
|
|
|
- // safe to assume it's a genuine program.
|
|
|
- if native_loader::check_id(account.owner()) {
|
|
|
- Some(account)
|
|
|
- } else {
|
|
|
- // malicious account is pre-occupying at program_id
|
|
|
- self.burn_and_purge_account(program_id, account);
|
|
|
- None
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- // introducing builtin program
|
|
|
- if existing_genuine_program.is_some() {
|
|
|
- // The existing account is sufficient
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- assert!(
|
|
|
- !self.freeze_started(),
|
|
|
- "Can't change frozen bank by adding not-existing new builtin program ({name}, \
|
|
|
- {program_id}). Maybe, inconsistent program activation is detected on snapshot \
|
|
|
- restore?"
|
|
|
- );
|
|
|
-
|
|
|
- // Add a bogus executable builtin account, which will be loaded and ignored.
|
|
|
- let (lamports, rent_epoch) =
|
|
|
- self.inherit_specially_retained_account_fields(&existing_genuine_program);
|
|
|
- let account: AccountSharedData = AccountSharedData::from(Account {
|
|
|
- lamports,
|
|
|
- data: name.as_bytes().to_vec(),
|
|
|
- owner: solana_sdk_ids::native_loader::id(),
|
|
|
- executable: true,
|
|
|
- rent_epoch,
|
|
|
- });
|
|
|
- self.store_account_and_update_capitalization(program_id, &account);
|
|
|
- }
|
|
|
-
|
|
|
fn inspect_account(&self, address: &Pubkey, account_state: AccountState, is_writable: bool) {
|
|
|
self.inspect_account_for_accounts_lt_hash(address, &account_state, is_writable);
|
|
|
}
|