Skip to content

Commit

Permalink
Test Validator: Set deployment slot to 0 for cloned upgradeable pro…
Browse files Browse the repository at this point in the history
…grams (solana-labs#501)

test-validator: clone upgradeable programs with slot 0
  • Loading branch information
buffalojoec authored Mar 29, 2024
1 parent fb1ee78 commit 4b0e7d6
Showing 1 changed file with 70 additions and 4 deletions.
74 changes: 70 additions & 4 deletions test-validator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use {
snapshot_config::SnapshotConfig,
},
solana_sdk::{
account::{Account, AccountSharedData},
account::{Account, AccountSharedData, WritableAccount},
bpf_loader_upgradeable::UpgradeableLoaderState,
clock::{Slot, DEFAULT_MS_PER_SLOT},
commitment_config::CommitmentConfig,
Expand Down Expand Up @@ -305,14 +305,16 @@ impl TestValidatorGenesis {
self
}

pub fn clone_accounts<T>(
fn clone_accounts_and_transform<T, F>(
&mut self,
addresses: T,
rpc_client: &RpcClient,
skip_missing: bool,
transform: F,
) -> Result<&mut Self, String>
where
T: IntoIterator<Item = Pubkey>,
F: Fn(&Pubkey, Account) -> Result<AccountSharedData, String>,
{
let addresses: Vec<Pubkey> = addresses.into_iter().collect();
for chunk in addresses.chunks(MAX_MULTIPLE_ACCOUNTS) {
Expand All @@ -322,7 +324,7 @@ impl TestValidatorGenesis {
.map_err(|err| format!("Failed to fetch: {err}"))?;
for (address, res) in chunk.iter().zip(responses) {
if let Some(account) = res {
self.add_account(*address, AccountSharedData::from(account));
self.add_account(*address, transform(address, account)?);
} else if skip_missing {
warn!("Could not find {}, skipping.", address);
} else {
Expand All @@ -333,6 +335,70 @@ impl TestValidatorGenesis {
Ok(self)
}

pub fn clone_accounts<T>(
&mut self,
addresses: T,
rpc_client: &RpcClient,
skip_missing: bool,
) -> Result<&mut Self, String>
where
T: IntoIterator<Item = Pubkey>,
{
self.clone_accounts_and_transform(
addresses,
rpc_client,
skip_missing,
|_address, account| Ok(AccountSharedData::from(account)),
)
}

pub fn clone_programdata_accounts<T>(
&mut self,
addresses: T,
rpc_client: &RpcClient,
skip_missing: bool,
) -> Result<&mut Self, String>
where
T: IntoIterator<Item = Pubkey>,
{
self.clone_accounts_and_transform(
addresses,
rpc_client,
skip_missing,
|address, account| {
let programdata_offset = UpgradeableLoaderState::size_of_programdata_metadata();
// Ensure the account is a proper programdata account before
// attempting to serialize into it.
if let Ok(UpgradeableLoaderState::ProgramData {
upgrade_authority_address,
..
}) = bincode::deserialize(&account.data[..programdata_offset])
{
// Serialize new programdata metadata into the resulting account,
// to overwrite the deployment slot to `0`.
let mut programdata_account = AccountSharedData::from(account);
bincode::serialize_into(
programdata_account.data_as_mut_slice(),
&UpgradeableLoaderState::ProgramData {
slot: 0,
upgrade_authority_address,
},
)
.map(|()| Ok(programdata_account))
.unwrap_or_else(|_| {
Err(format!(
"Failed to write to upgradeable programdata account {address}",
))
})
} else {
Err(format!(
"Failed to read upgradeable programdata account {address}",
))
}
},
)
}

pub fn clone_upgradeable_programs<T>(
&mut self,
addresses: T,
Expand Down Expand Up @@ -360,7 +426,7 @@ impl TestValidatorGenesis {
}
}

self.clone_accounts(programdata_addresses, rpc_client, false)?;
self.clone_programdata_accounts(programdata_addresses, rpc_client, false)?;

Ok(self)
}
Expand Down

0 comments on commit 4b0e7d6

Please sign in to comment.