Skip to content

Commit

Permalink
runtime: core_bpf_migration: add migration path
Browse files Browse the repository at this point in the history
  • Loading branch information
buffalojoec committed Feb 19, 2024
1 parent 543a3aa commit 9fac58c
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#![allow(dead_code)] // Removed in later commit
use {
super::error::CoreBpfMigrationError,
crate::bank::Bank,
Expand Down
1 change: 0 additions & 1 deletion runtime/src/bank/builtins/core_bpf_migration/builtin.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#![allow(dead_code)] // Removed in later commit
use {
super::{error::CoreBpfMigrationError, CoreBpfMigration},
crate::bank::Bank,
Expand Down
3 changes: 3 additions & 0 deletions runtime/src/bank/builtins/core_bpf_migration/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ pub enum CoreBpfMigrationError {
/// Invalid program data account
#[error("Invalid program data account: {0:?}")]
InvalidProgramDataAccount(Pubkey),
/// Failed to serialize new program account
#[error("Failed to serialize new program account")]
FailedToSerialize,
// Since `core_bpf_migration` does not return `ProgramError` or
// `InstructionError`, we have to duplicate `ArithmeticOverflow` here.
/// Arithmetic overflow
Expand Down
88 changes: 85 additions & 3 deletions runtime/src/bank/builtins/core_bpf_migration/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
#![allow(dead_code)] // Removed in later commit
mod bpf_upgradeable;
mod builtin;
mod error;
pub(crate) mod error;

use solana_sdk::pubkey::Pubkey;
use {
crate::bank::Bank,
bpf_upgradeable::BpfUpgradeableConfig,
builtin::BuiltinConfig,
error::CoreBpfMigrationError,
solana_sdk::{
account::{Account, AccountSharedData},
bpf_loader_upgradeable::{UpgradeableLoaderState, ID as BPF_LOADER_UPGRADEABLE_ID},
pubkey::Pubkey,
},
std::sync::atomic::Ordering::Relaxed,
};

/// Sets up a Core BPF migration for a built-in program.
pub enum CoreBpfMigration {
Expand All @@ -15,6 +25,7 @@ pub enum CoreBpfMigration {
pub struct CoreBpfMigrationConfig {
pub source_program_id: Pubkey,
pub feature_id: Pubkey,
pub datapoint_name: &'static str,
}

impl std::fmt::Debug for CoreBpfMigrationConfig {
Expand All @@ -25,3 +36,74 @@ impl std::fmt::Debug for CoreBpfMigrationConfig {
builder.finish()
}
}

/// Create a new `Account` with a pointer to the target's new data account.
///
/// Note the pointer is created manually, as well as the owner and
/// executable values. The rest is inherited from the source program
/// account, including the lamports.
fn create_new_target_program_account(
target: &BuiltinConfig,
source: &BpfUpgradeableConfig,
) -> Result<AccountSharedData, CoreBpfMigrationError> {
let state = UpgradeableLoaderState::Program {
programdata_address: target.program_data_address,
};
let data = bincode::serialize(&state).map_err(|_| CoreBpfMigrationError::FailedToSerialize)?;
let account = Account {
data,
owner: BPF_LOADER_UPGRADEABLE_ID,
executable: true,
..source.program_account
};
Ok(AccountSharedData::from(account))
}

impl CoreBpfMigrationConfig {
pub(crate) fn migrate_builtin_to_core_bpf(
&self,
bank: &mut Bank,
program_id: &Pubkey,
migration: CoreBpfMigration,
) -> Result<(), CoreBpfMigrationError> {
datapoint_info!(self.datapoint_name, ("slot", bank.slot, i64));

let target = BuiltinConfig::new_checked(bank, program_id, migration)?;
let source = BpfUpgradeableConfig::new_checked(bank, &self.source_program_id)?;

// Attempt serialization first before touching the bank
let new_target_program_account = create_new_target_program_account(&target, &source)?;

// Burn lamports from the target program account
bank.capitalization
.fetch_sub(target.program_account.lamports, Relaxed);

// Replace the native program account with the created to point to the new data
// account and clear the source program account
bank.store_account(&target.program_address, &new_target_program_account);
bank.store_account(&source.program_address, &AccountSharedData::default());

// Copy the upgradeable BPF program's data account into the native
// program's data address, which is checked to be empty, then clear the
// upgradeable BPF program's data account.
bank.store_account(&target.program_data_address, &source.program_data_account);
bank.store_account(&source.program_data_address, &AccountSharedData::default());

// Update the account data size delta.
bank.calculate_and_update_accounts_data_size_delta_off_chain(
target.total_data_size,
source.total_data_size,
);

// Remove the built-in program from the bank's list of built-ins
bank.builtin_programs.remove(&target.program_address);

// Unload the programs from the bank's cache
bank.loaded_programs_cache
.write()
.unwrap()
.remove_programs([source.program_address, target.program_address].into_iter());

Ok(())
}
}
35 changes: 33 additions & 2 deletions runtime/src/bank/builtins/prototypes.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#![allow(dead_code)] // Removed in later commit
use {
super::core_bpf_migration::CoreBpfMigrationConfig,
solana_program_runtime::invoke_context::BuiltinFunctionWithContext, solana_sdk::pubkey::Pubkey,
super::core_bpf_migration::{
error::CoreBpfMigrationError, CoreBpfMigration, CoreBpfMigrationConfig,
},
crate::bank::Bank,
solana_program_runtime::invoke_context::BuiltinFunctionWithContext,
solana_sdk::pubkey::Pubkey,
};

/// Transitions of built-in programs at epoch boundaries when features are activated.
Expand All @@ -23,6 +28,19 @@ impl std::fmt::Debug for BuiltinPrototype {
}
}

impl BuiltinPrototype {
pub(crate) fn migrate_to_core_bpf(&self, bank: &mut Bank) -> Result<(), CoreBpfMigrationError> {
if let Some(config) = &self.core_bpf_migration {
config.migrate_builtin_to_core_bpf(
bank,
&self.program_id,
CoreBpfMigration::Builtin,
)?;
}
Ok(())
}
}

#[cfg(RUSTC_WITH_SPECIALIZATION)]
impl solana_frozen_abi::abi_example::AbiExample for BuiltinPrototype {
fn example() -> Self {
Expand Down Expand Up @@ -60,3 +78,16 @@ impl std::fmt::Debug for EphemeralBuiltinPrototype {
builder.finish()
}
}

impl EphemeralBuiltinPrototype {
pub(crate) fn migrate_to_core_bpf(&self, bank: &mut Bank) -> Result<(), CoreBpfMigrationError> {
if let Some(config) = &self.core_bpf_migration {
config.migrate_builtin_to_core_bpf(
bank,
&self.program_id,
CoreBpfMigration::Ephemeral,
)?;
}
Ok(())
}
}

0 comments on commit 9fac58c

Please sign in to comment.