Test Validator: Set deployment slot to `0` for cloned upgradeable programs (#501)

test-validator: clone upgradeable programs with slot 0
This commit is contained in:
Joe C 2024-03-29 17:05:53 -05:00 committed by GitHub
parent fb1ee7842f
commit 4b0e7d6ba3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 70 additions and 4 deletions

View File

@ -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,
@ -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) {
@ -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 {
@ -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,
@ -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)
}