miner migration

This commit is contained in:
Hardhat Chad
2025-08-28 13:29:57 -07:00
parent e17a90db4a
commit 53b340268d
8 changed files with 155 additions and 5 deletions

View File

@@ -11,7 +11,7 @@ description = "Digial gold, unchained."
documentation = "https://docs.rs/ore-api/latest/ore_api/"
repository = "https://github.com/regolith-labs/ore"
readme = "./README.md"
keywords = ["solana", "crypto", "mining"]
keywords = ["solana"]
[workspace.dependencies]
anyhow = "1.0"

View File

@@ -19,6 +19,9 @@ pub enum OreInstruction {
SetFeeCollector = 10,
SetFeeRate = 11,
SetSniperFeeDuration = 12,
// Migration
MigrateMinerAccount = 13,
}
#[repr(C)]
@@ -100,6 +103,12 @@ pub struct SetSniperFeeDuration {
pub sniper_fee_duration: [u8; 8],
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct MigrateMinerAccount {
pub authority: [u8; 32],
}
instruction!(OreInstruction, Claim);
instruction!(OreInstruction, Open);
instruction!(OreInstruction, Close);
@@ -113,3 +122,4 @@ instruction!(OreInstruction, SetBlockDuration);
instruction!(OreInstruction, SetFeeCollector);
instruction!(OreInstruction, SetFeeRate);
instruction!(OreInstruction, SetSniperFeeDuration);
instruction!(OreInstruction, MigrateMinerAccount);

View File

@@ -287,3 +287,20 @@ pub fn set_sniper_fee_duration(signer: Pubkey, sniper_fee_duration: u64) -> Inst
.to_bytes(),
}
}
pub fn migrate_miner_account(signer: Pubkey, miner: Pubkey) -> Instruction {
let config_address = config_pda().0;
Instruction {
program_id: crate::ID,
accounts: vec![
AccountMeta::new(signer, true),
AccountMeta::new(config_address, false),
AccountMeta::new(miner, false),
AccountMeta::new_readonly(system_program::ID, false),
],
data: MigrateMinerAccount {
authority: miner.to_bytes(),
}
.to_bytes(),
}
}

View File

@@ -1,9 +1,31 @@
use steel::*;
use crate::state::miner_pda;
use crate::state::{miner_pda, OreAccountOLD};
use super::OreAccount;
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
pub struct MinerOLD {
/// The authority of this miner account.
pub authority: Pubkey,
/// The ID of the last block this miner mined in.
pub block_id: u64,
/// The amount of hashpower this miner has committed to the current block.
pub hashpower: u64,
/// A user-supplied seed for random number generation.
pub seed: [u8; 32],
/// The total amount of hashpower this miner has committed across all blocks.
pub total_hashpower: u64,
/// The total amount of ORE this miner has mined across all blocks.
pub total_rewards: u64,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
pub struct Miner {
@@ -13,6 +35,9 @@ pub struct Miner {
/// The ID of the last block this miner mined in.
pub block_id: u64,
/// An account authorized to execute actions on behalf of this miner.
pub executor: Pubkey,
/// The amount of hashpower this miner has committed to the current block.
pub hashpower: u64,
@@ -33,3 +58,4 @@ impl Miner {
}
account!(OreAccount, Miner);
account!(OreAccountOLD, MinerOLD);

View File

@@ -24,6 +24,12 @@ pub enum OreAccount {
Treasury = 104,
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
pub enum OreAccountOLD {
MinerOLD = 103,
}
pub fn block_pda(id: u64) -> (Pubkey, u8) {
Pubkey::find_program_address(&[BLOCK, &id.to_le_bytes()], &crate::ID)
}

View File

@@ -81,6 +81,9 @@ async fn main() {
"set_fee_collector" => {
set_fee_collector(&rpc, &payer).await.unwrap();
}
"migrate" => {
migrate(&rpc, &payer).await.unwrap();
}
"benchmark" => {
benchmark_keccak().await.unwrap();
}
@@ -241,6 +244,36 @@ async fn set_fee_collector(
Ok(())
}
async fn migrate(
rpc: &RpcClient,
payer: &solana_sdk::signer::keypair::Keypair,
) -> Result<(), anyhow::Error> {
let address = std::env::var("ADDRESS").expect("Missing ADDRESS env var");
let address = Pubkey::from_str(&address).expect("Invalid ADDRESS");
let ix = ore_api::sdk::migrate_miner_account(payer.pubkey(), address);
simulate_transaction(rpc, payer, &[ix]).await;
Ok(())
}
async fn migrate_all(
rpc: &RpcClient,
payer: &solana_sdk::signer::keypair::Keypair,
) -> Result<(), anyhow::Error> {
let old_miners = get_old_miners(rpc).await?;
println!("Found {} old miners", old_miners.len());
for (i, (miner_address, _)) in old_miners.iter().enumerate() {
println!(
"[{} / {}] Migrating miner {}",
i,
old_miners.len(),
miner_address
);
let ix = ore_api::sdk::migrate_miner_account(payer.pubkey(), *miner_address);
simulate_transaction(rpc, payer, &[ix]).await;
}
Ok(())
}
async fn log_treasury(_rpc: &RpcClient) -> Result<(), anyhow::Error> {
let treasury_address = ore_api::state::treasury_pda().0;
println!("Treasury");
@@ -367,10 +400,10 @@ async fn get_market(rpc: &RpcClient) -> Result<Market, anyhow::Error> {
Ok(*market)
}
async fn get_miner(rpc: &RpcClient, authority: Pubkey) -> Result<Miner, anyhow::Error> {
async fn get_miner(rpc: &RpcClient, authority: Pubkey) -> Result<MinerOLD, anyhow::Error> {
let miner_pda = ore_api::state::miner_pda(authority);
let account = rpc.get_account(&miner_pda.0).await?;
let miner = Miner::try_from_bytes(&account.data)?;
let miner = MinerOLD::try_from_bytes(&account.data)?;
Ok(*miner)
}
@@ -385,7 +418,18 @@ async fn get_blocks(rpc: &RpcClient) -> Result<Vec<(Pubkey, Block)>, anyhow::Err
Ok(blocks)
}
async fn _simulate_transaction(
async fn get_old_miners(rpc: &RpcClient) -> Result<Vec<(Pubkey, MinerOLD)>, anyhow::Error> {
let miners = get_program_accounts::<MinerOLD>(rpc, ore_api::ID, vec![]).await?;
Ok(miners)
}
async fn get_miners(rpc: &RpcClient) -> Result<Vec<(Pubkey, Miner)>, anyhow::Error> {
let miners = get_program_accounts::<Miner>(rpc, ore_api::ID, vec![]).await?;
Ok(miners)
}
#[allow(dead_code)]
async fn simulate_transaction(
rpc: &RpcClient,
payer: &solana_sdk::signer::keypair::Keypair,
instructions: &[solana_sdk::instruction::Instruction],

View File

@@ -2,6 +2,7 @@ mod claim;
mod close;
mod initialize;
mod log;
mod migrate_miner_account;
mod mine;
mod open;
mod reset;
@@ -17,6 +18,7 @@ use claim::*;
use close::*;
use initialize::*;
use log::*;
use migrate_miner_account::*;
use mine::*;
use open::*;
use reset::*;
@@ -54,6 +56,9 @@ pub fn process_instruction(
OreInstruction::SetFeeCollector => process_set_fee_collector(accounts, data)?,
OreInstruction::SetFeeRate => process_set_fee_rate(accounts, data)?,
OreInstruction::SetSniperFeeDuration => process_set_sniper_fee_duration(accounts, data)?,
// Migration
OreInstruction::MigrateMinerAccount => process_migrate_miner_account(accounts, data)?,
}
Ok(())

View File

@@ -0,0 +1,42 @@
use std::mem::size_of;
use ore_api::prelude::*;
use solana_program::log::sol_log;
use steel::*;
/// Migrates a miner account from the old format to the new format.
pub fn process_migrate_miner_account(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
// Load accounts.
let [signer_info, config_info, miner_info, system_program] = accounts else {
return Err(ProgramError::NotEnoughAccountKeys);
};
signer_info.is_signer()?;
config_info
.as_account_mut::<Config>(&ore_api::ID)?
.assert_mut(|c| c.admin == *signer_info.key)?;
let miner = miner_info.as_account_mut::<MinerOLD>(&ore_api::ID)?;
system_program.is_program(&system_program::ID)?;
// Copy old data.
let authority = miner.authority;
let block_id = miner.block_id;
let hashpower = miner.hashpower;
let seed = miner.seed;
let total_hashpower = miner.total_hashpower;
let total_rewards = miner.total_rewards;
// Reallocate new account.
miner_info.realloc(8 + size_of::<Miner>(), false)?;
// Copy new data.
let miner = miner_info.as_account_mut::<Miner>(&ore_api::ID)?;
miner.authority = authority;
miner.block_id = block_id;
miner.executor = Pubkey::default();
miner.hashpower = hashpower;
miner.seed = seed;
miner.total_hashpower = total_hashpower;
miner.total_rewards = total_rewards;
Ok(())
}