-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #22 from VegetarianOrc/migrate
add method to migrate storage accts. Closes #15 when merged
- Loading branch information
Showing
4 changed files
with
189 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
use byte_unit::Byte; | ||
use shadow_drive_rust::{ShadowDriveClient, StorageAccountVersion}; | ||
use solana_client::nonblocking::rpc_client::RpcClient; | ||
use solana_sdk::{ | ||
commitment_config::CommitmentConfig, pubkey::Pubkey, signer::keypair::read_keypair_file, | ||
}; | ||
use std::str::FromStr; | ||
use std::time::Duration; | ||
|
||
const KEYPAIR_PATH: &str = "keypair.json"; | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
//load keypair from file | ||
let keypair = read_keypair_file(KEYPAIR_PATH).expect("failed to load keypair at path"); | ||
|
||
//create shdw drive client | ||
let shdw_drive_client = ShadowDriveClient::new(keypair, "https://ssc-dao.genesysgo.net"); | ||
|
||
// create V1 storage account | ||
let v1_response = shdw_drive_client | ||
.create_storage_account( | ||
"1.5-test", | ||
Byte::from_str("1MB").expect("invalid byte string"), | ||
StorageAccountVersion::v1(), | ||
) | ||
.await | ||
.expect("error creating storage account"); | ||
|
||
println!("v1: {:?} \n", v1_response); | ||
|
||
let key_string: String = v1_response.shdw_bucket.unwrap(); | ||
let v1_pubkey: Pubkey = Pubkey::from_str(&key_string).unwrap(); | ||
|
||
// can migrate all at once | ||
let migrate = shdw_drive_client | ||
.migrate(&v1_pubkey) | ||
.await | ||
.expect("failed to migrate"); | ||
println!("Migrated {:?} \n", migrate); | ||
|
||
// alternatively can split migration into 2 steps (boths steps are exposed) | ||
|
||
// // step 1 | ||
// let migrate_step_1 = shdw_drive_client | ||
// .migrate_step_1(&v1_pubkey) | ||
// .await | ||
// .expect("failed to migrate v1 step 1"); | ||
// println!("Step 1 complete {:?} \n", migrate_step_1); | ||
|
||
// // step 2 | ||
// let migrate_step_2 = shdw_drive_client | ||
// .migrate_step_2(&v1_pubkey) | ||
// .await | ||
// .expect("failed to migrate v1 step 2"); | ||
// println!("Step 2 complete {:?} \n", migrate_step_2); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
use anchor_lang::{system_program, InstructionData, ToAccountMetas}; | ||
use shadow_drive_user_staking::accounts as shdw_drive_accounts; | ||
use shadow_drive_user_staking::instruction as shdw_drive_instructions; | ||
use solana_sdk::{ | ||
instruction::Instruction, pubkey::Pubkey, signer::Signer, transaction::Transaction, | ||
}; | ||
|
||
use super::ShadowDriveClient; | ||
|
||
use crate::{constants::PROGRAM_ADDRESS, derived_addresses, models::*}; | ||
|
||
impl<T> ShadowDriveClient<T> | ||
where | ||
T: Signer + Send + Sync, | ||
{ | ||
/// Migrates a v1 [`StorageAccount`](crate::models::StorageAccount) to v2. | ||
/// This requires two separate transactions to reuse the original pubkey. To minimize chance of failure, it is recommended to call this method with a [commitment level][cl] of [`Finalized`](solana_sdk::commitment_config::CommitmentLevel::Finalized) | ||
/// | ||
/// [cl]: https://docs.solana.com/developing/clients/jsonrpc-api#configuring-state-commitment | ||
/// | ||
/// * `storage_account_key` - The public key of the [`StorageAccount`](crate::models::StorageAccount) to be migrated. | ||
/// | ||
/// # Example | ||
/// | ||
/// ``` | ||
/// # use shadow_drive_rust::{ShadowDriveClient, derived_addresses::storage_account}; | ||
/// # use solana_client::rpc_client::RpcClient; | ||
/// # use solana_sdk::{ | ||
/// # pubkey::Pubkey, | ||
/// # signature::Keypair, | ||
/// # signer::{keypair::read_keypair_file, Signer}, | ||
/// # }; | ||
/// # | ||
/// # let keypair = read_keypair_file(KEYPAIR_PATH).expect("failed to load keypair at path"); | ||
/// # let user_pubkey = keypair.pubkey(); | ||
/// # let rpc_client = RpcClient::new("https://ssc-dao.genesysgo.net"); | ||
/// # let shdw_drive_client = ShadowDriveClient::new(keypair, rpc_client); | ||
/// # let (storage_account_key, _) = storage_account(&user_pubkey, 0); | ||
/// # | ||
///let migrate_response = shdw_drive_client | ||
/// .migrate(&storage_account_key) | ||
/// .await?; | ||
/// ``` | ||
pub async fn migrate( | ||
&self, | ||
storage_account_key: &Pubkey, | ||
) -> ShadowDriveResult<(ShdwDriveResponse, ShdwDriveResponse)> { | ||
let step_1_response = self.migrate_step_1(storage_account_key).await?; | ||
let step_2_response = self.migrate_step_2(storage_account_key).await?; | ||
Ok((step_1_response, step_2_response)) | ||
} | ||
|
||
/// First transaction step that migrates a v1 [`StorageAccount`](crate::models::StorageAccount) to v2. | ||
/// Consists of copying the existing account's data into an intermediate account, and deleting the v1 storage account | ||
pub async fn migrate_step_1( | ||
&self, | ||
storage_account_key: &Pubkey, | ||
) -> ShadowDriveResult<ShdwDriveResponse> { | ||
let wallet_pubkey = self.wallet.pubkey(); | ||
let (migration, _) = derived_addresses::migration_helper(storage_account_key); | ||
|
||
let accounts = shdw_drive_accounts::MigrateStep1 { | ||
storage_account: *storage_account_key, | ||
migration, | ||
owner: wallet_pubkey, | ||
system_program: system_program::ID, | ||
}; | ||
|
||
let args = shdw_drive_instructions::MigrateStep1 {}; | ||
|
||
let instruction = Instruction { | ||
program_id: PROGRAM_ADDRESS, | ||
accounts: accounts.to_account_metas(None), | ||
data: args.data(), | ||
}; | ||
|
||
let mut txn = Transaction::new_with_payer(&[instruction], Some(&wallet_pubkey)); | ||
txn.try_sign( | ||
&[&self.wallet], | ||
self.rpc_client.get_latest_blockhash().await?, | ||
)?; | ||
let txn_result = self.rpc_client.send_and_confirm_transaction(&txn).await?; | ||
|
||
Ok(ShdwDriveResponse { | ||
txid: txn_result.to_string(), | ||
}) | ||
} | ||
/// Second transaction step that migrates a v1 [`StorageAccount`](crate::models::StorageAccount) to v2. | ||
/// Consists of recreating the storage account using the original pubkey, and deleting the intermediate account | ||
pub async fn migrate_step_2( | ||
&self, | ||
storage_account_key: &Pubkey, | ||
) -> ShadowDriveResult<ShdwDriveResponse> { | ||
let wallet_pubkey = self.wallet.pubkey(); | ||
let (migration, _) = derived_addresses::migration_helper(storage_account_key); | ||
|
||
let accounts = shdw_drive_accounts::MigrateStep2 { | ||
storage_account: *storage_account_key, | ||
migration, | ||
owner: wallet_pubkey, | ||
system_program: system_program::ID, | ||
}; | ||
|
||
let args = shdw_drive_instructions::MigrateStep2 {}; | ||
|
||
let instruction = Instruction { | ||
program_id: PROGRAM_ADDRESS, | ||
accounts: accounts.to_account_metas(None), | ||
data: args.data(), | ||
}; | ||
|
||
let mut txn = Transaction::new_with_payer(&[instruction], Some(&wallet_pubkey)); | ||
txn.try_sign( | ||
&[&self.wallet], | ||
self.rpc_client.get_latest_blockhash().await?, | ||
)?; | ||
let txn_result = self.rpc_client.send_and_confirm_transaction(&txn).await?; | ||
|
||
Ok(ShdwDriveResponse { | ||
txid: txn_result.to_string(), | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters