From 71dcac553a1c947e28942464fe19af20343270b9 Mon Sep 17 00:00:00 2001 From: Hardhat Chad Date: Sun, 28 Apr 2024 17:06:36 +0000 Subject: [PATCH] reset --- Cargo.lock | 7 ++ Cargo.toml | 1 + src/consts.rs | 31 +++---- src/lib.rs | 1 + src/processor/initialize.rs | 4 +- src/processor/mine.rs | 2 +- src/processor/reset.rs | 163 +++++++++++++++++++----------------- src/processor/upgrade.rs | 4 +- src/state/config.rs | 3 + src/state/treasury.rs | 1 + 10 files changed, 119 insertions(+), 98 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4ee9711..79e32c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -278,6 +278,12 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "array-const-fn-init" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bcb85e548c05d407fa6faff46b750ba287714ef32afc0f5e15b4641ffd6affb" + [[package]] name = "arrayref" version = "0.3.7" @@ -2546,6 +2552,7 @@ dependencies = [ name = "ore-program" version = "1.2.1" dependencies = [ + "array-const-fn-init", "bs58 0.5.1", "bs64", "bytemuck", diff --git a/Cargo.toml b/Cargo.toml index 9b8ab90..5de42fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ no-entrypoint = [] default = [] [dependencies] +array-const-fn-init = "0.1.1" bs58 = "0.5.0" bytemuck = "1.14.3" const-crypto = "0.1.0" diff --git a/src/consts.rs b/src/consts.rs index 304ff1f..9ca222d 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,15 +1,11 @@ +use array_const_fn_init::array_const_fn_init; use const_crypto::ed25519; -use solana_program::{keccak::Hash, pubkey, pubkey::Pubkey}; +use solana_program::{pubkey, pubkey::Pubkey}; /// The reward rate to intialize the program with. -pub const INITIAL_REWARD_RATE: u64 = 10u64.pow(3u32); - -/// The mining difficulty to initialize the program with. -pub const INITIAL_DIFFICULTY: Hash = Hash::new_from_array([ - 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, -]); +pub const INITIAL_BASE_REWARD_RATE: u64 = 10u64.pow(3u32); +// TODO Migrate to 11 decimals? /// The decimal precision of the ORE token. /// Using SI prefixes, the smallest indivisible unit of ORE is a nanoORE. /// 1 nanoORE = 0.000000001 ORE = one billionth of an ORE @@ -82,16 +78,12 @@ pub const METADATA_URI: &str = "https://ore.supply/metadata.json"; const PROGRAM_ID: [u8; 32] = unsafe { *(&crate::id() as *const Pubkey as *const [u8; 32]) }; /// The addresses of the bus accounts. -pub const BUS_ADDRESSES: [Pubkey; BUS_COUNT] = [ - Pubkey::new_from_array(ed25519::derive_program_address(&[BUS, &[0]], &PROGRAM_ID).0), - Pubkey::new_from_array(ed25519::derive_program_address(&[BUS, &[1]], &PROGRAM_ID).0), - Pubkey::new_from_array(ed25519::derive_program_address(&[BUS, &[2]], &PROGRAM_ID).0), - Pubkey::new_from_array(ed25519::derive_program_address(&[BUS, &[3]], &PROGRAM_ID).0), - Pubkey::new_from_array(ed25519::derive_program_address(&[BUS, &[4]], &PROGRAM_ID).0), - Pubkey::new_from_array(ed25519::derive_program_address(&[BUS, &[5]], &PROGRAM_ID).0), - Pubkey::new_from_array(ed25519::derive_program_address(&[BUS, &[6]], &PROGRAM_ID).0), - Pubkey::new_from_array(ed25519::derive_program_address(&[BUS, &[7]], &PROGRAM_ID).0), -]; +pub const BUS_ADDRESSES: [Pubkey; BUS_COUNT] = array_const_fn_init![const_bus_address; 8]; + +/// Function to derive const bus addresses. +const fn const_bus_address(i: usize) -> Pubkey { + Pubkey::new_from_array(ed25519::derive_program_address(&[BUS, &[i as u8]], &PROGRAM_ID).0) +} /// The address of the config account. pub const CONFIG_ADDRESS: Pubkey = @@ -124,3 +116,6 @@ pub const NOISE_ADDRESS: Pubkey = /// The address of the treasury account. pub const TREASURY_ADDRESS: Pubkey = Pubkey::new_from_array(ed25519::derive_program_address(&[TREASURY], &PROGRAM_ID).0); + +/// The bump of the treasury account, for cpis. +pub const TREASURY_BUMP: u8 = ed25519::derive_program_address(&[TREASURY], &PROGRAM_ID).1; diff --git a/src/lib.rs b/src/lib.rs index dc85594..e20901d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ use solana_program::{ program_error::ProgramError, pubkey::Pubkey, }; +// TODO u128 for internal rewards representation? // TODO Is downgrade necessary or no? declare_id!("mineRHF5r6S7HyD9SppBfVMXMavDkJsxwGesEvxZr2A"); diff --git a/src/processor/initialize.rs b/src/processor/initialize.rs index 2e6b23f..2c90ea3 100644 --- a/src/processor/initialize.rs +++ b/src/processor/initialize.rs @@ -118,7 +118,7 @@ pub fn process_initialize<'a, 'info>( bus.rewards = 0; } - // Initialize config + // TODO Initialize config create_pda( config_info, &crate::id(), @@ -133,7 +133,7 @@ pub fn process_initialize<'a, 'info>( config.admin = *signer.key; // config.difficulty = INITIAL_DIFFICULTY.into(); - // Initialize treasury + // TODO Initialize treasury create_pda( treasury_info, &crate::id(), diff --git a/src/processor/mine.rs b/src/processor/mine.rs index daf02fa..e941040 100644 --- a/src/processor/mine.rs +++ b/src/processor/mine.rs @@ -54,7 +54,7 @@ pub fn process_mine<'a, 'info>( load_proof(proof_info, signer.key, true)?; load_sysvar(slot_hashes_info, sysvar::slot_hashes::id())?; - // Validate mining is allowed + // Validate mining is not paused let config_data = config_info.data.borrow(); let config = Config::try_from_bytes(&config_data)?; if config.paused.ne(&0) { diff --git a/src/processor/reset.rs b/src/processor/reset.rs index 26db329..b4dc799 100644 --- a/src/processor/reset.rs +++ b/src/processor/reset.rs @@ -1,6 +1,19 @@ -use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}; +use solana_program::{ + account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, + program_error::ProgramError, pubkey::Pubkey, sysvar::Sysvar, +}; -use crate::{BUS_EPOCH_REWARDS, SMOOTHING_FACTOR, TARGET_EPOCH_REWARDS}; +use crate::{ + error::OreError, + loaders::{ + load_bus, load_config, load_mint, load_program, load_signer, load_token_account, + load_treasury, + }, + state::{Bus, Config}, + utils::AccountDeserialize, + BUS_COUNT, BUS_EPOCH_REWARDS, EPOCH_DURATION, MAX_EPOCH_REWARDS, MINT_ADDRESS, + SMOOTHING_FACTOR, TARGET_EPOCH_REWARDS, TREASURY, TREASURY_BUMP, +}; /// Reset sets up the Ore program for the next epoch. Its responsibilities include: /// 1. Reset bus account rewards counters. @@ -23,85 +36,85 @@ pub fn process_reset<'a, 'info>( accounts: &'a [AccountInfo<'info>], _data: &[u8], ) -> ProgramResult { - // // Load accounts - // let [signer, bus_0_info, bus_1_info, bus_2_info, bus_3_info, bus_4_info, bus_5_info, bus_6_info, bus_7_info, mint_info, treasury_info, treasury_tokens_info, token_program] = - // accounts - // else { - // return Err(ProgramError::NotEnoughAccountKeys); - // }; - // load_signer(signer)?; - // load_bus(bus_0_info, 0, true)?; - // load_bus(bus_1_info, 1, true)?; - // load_bus(bus_2_info, 2, true)?; - // load_bus(bus_3_info, 3, true)?; - // load_bus(bus_4_info, 4, true)?; - // load_bus(bus_5_info, 5, true)?; - // load_bus(bus_6_info, 6, true)?; - // load_bus(bus_7_info, 7, true)?; - // load_mint(mint_info, true)?; - // load_treasury(treasury_info, true)?; - // load_token_account( - // treasury_tokens_info, - // Some(treasury_info.key), - // mint_info.key, - // true, - // )?; - // load_program(token_program, spl_token::id())?; - // let busses: [&AccountInfo; BUS_COUNT] = [ - // bus_0_info, bus_1_info, bus_2_info, bus_3_info, bus_4_info, bus_5_info, bus_6_info, - // bus_7_info, - // ]; + // Load accounts + let [signer, bus_0_info, bus_1_info, bus_2_info, bus_3_info, bus_4_info, bus_5_info, bus_6_info, bus_7_info, config_info, mint_info, treasury_info, treasury_tokens_info, token_program] = + accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + load_signer(signer)?; + load_bus(bus_0_info, 0, true)?; + load_bus(bus_1_info, 1, true)?; + load_bus(bus_2_info, 2, true)?; + load_bus(bus_3_info, 3, true)?; + load_bus(bus_4_info, 4, true)?; + load_bus(bus_5_info, 5, true)?; + load_bus(bus_6_info, 6, true)?; + load_bus(bus_7_info, 7, true)?; + load_config(config_info, true)?; + load_mint(mint_info, MINT_ADDRESS, true)?; + load_treasury(treasury_info, true)?; + load_token_account( + treasury_tokens_info, + Some(treasury_info.key), + mint_info.key, + true, + )?; + load_program(token_program, spl_token::id())?; + let busses: [&AccountInfo; BUS_COUNT] = [ + bus_0_info, bus_1_info, bus_2_info, bus_3_info, bus_4_info, bus_5_info, bus_6_info, + bus_7_info, + ]; - // // Validate mining has starting - // let clock = Clock::get().or(Err(ProgramError::InvalidAccountData))?; - // if clock.unix_timestamp.lt(&START_AT) { - // return Err(OreError::NotStarted.into()); - // } + // Validate mining is not paused + let mut config_data = config_info.data.borrow_mut(); + let config = Config::try_from_bytes_mut(&mut config_data)?; + if config.paused.ne(&0) { + return Err(OreError::IsPaused.into()); + } - // // Validate at least 60 seconds have passed since last reset - // let mut treasury_data = treasury_info.data.borrow_mut(); - // let treasury = Treasury::try_from_bytes_mut(&mut treasury_data)?; - // let threshold = treasury.last_reset_at.saturating_add(EPOCH_DURATION); - // if clock.unix_timestamp.lt(&threshold) { - // return Err(OreError::ResetTooEarly.into()); - // } + // Validate enough time has passed since last reset + let clock = Clock::get().or(Err(ProgramError::InvalidAccountData))?; + let threshold = config.last_reset_at.saturating_add(EPOCH_DURATION); + if clock.unix_timestamp.lt(&threshold) { + return Err(OreError::ResetTooEarly.into()); + } - // // Record current timestamp - // treasury.last_reset_at = clock.unix_timestamp; + // Update reset timestamp + config.last_reset_at = clock.unix_timestamp; - // // Reset bus accounts and calculate actual rewards mined since last reset - // let mut total_remaining_rewards = 0u64; - // for i in 0..BUS_COUNT { - // let mut bus_data = busses[i].data.borrow_mut(); - // let bus = Bus::try_from_bytes_mut(&mut bus_data)?; - // total_remaining_rewards = total_remaining_rewards.saturating_add(bus.rewards); - // bus.rewards = BUS_EPOCH_REWARDS; - // } - // let total_epoch_rewards = MAX_EPOCH_REWARDS.saturating_sub(total_remaining_rewards); + // Reset bus accounts and calculate actual rewards mined since last reset + let mut total_remaining_rewards = 0u64; + for i in 0..BUS_COUNT { + let mut bus_data = busses[i].data.borrow_mut(); + let bus = Bus::try_from_bytes_mut(&mut bus_data)?; + total_remaining_rewards = total_remaining_rewards.saturating_add(bus.rewards); + bus.rewards = BUS_EPOCH_REWARDS; + } + let total_epoch_rewards = MAX_EPOCH_REWARDS.saturating_sub(total_remaining_rewards); - // // Update reward rate for next epoch - // treasury.reward_rate = calculate_new_reward_rate(treasury.reward_rate, total_epoch_rewards); + // Update base reward rate for next epoch + config.base_reward_rate = + calculate_new_reward_rate(config.base_reward_rate, total_epoch_rewards); - // // Fund treasury token account - // let treasury_bump = treasury.bump as u8; - // drop(treasury_data); - // solana_program::program::invoke_signed( - // &spl_token::instruction::mint_to( - // &spl_token::id(), - // mint_info.key, - // treasury_tokens_info.key, - // treasury_info.key, - // &[treasury_info.key], - // total_epoch_rewards, - // )?, - // &[ - // token_program.clone(), - // mint_info.clone(), - // treasury_tokens_info.clone(), - // treasury_info.clone(), - // ], - // &[&[TREASURY, &[treasury_bump]]], - // )?; + // Fund treasury token account + solana_program::program::invoke_signed( + &spl_token::instruction::mint_to( + &spl_token::id(), + mint_info.key, + treasury_tokens_info.key, + treasury_info.key, + &[treasury_info.key], + total_epoch_rewards, + )?, + &[ + token_program.clone(), + mint_info.clone(), + treasury_tokens_info.clone(), + treasury_info.clone(), + ], + &[&[TREASURY, &[TREASURY_BUMP]]], + )?; Ok(()) } diff --git a/src/processor/upgrade.rs b/src/processor/upgrade.rs index 4788c17..fa4aeef 100644 --- a/src/processor/upgrade.rs +++ b/src/processor/upgrade.rs @@ -53,8 +53,8 @@ pub fn process_upgrade<'a, 'info>( ], )?; - // Mint to beneficiary account - // TODO Account for decimals! + // Mint to the beneficiary account + // TODO Account for decimals change! let treasury_data = treasury_info.data.borrow(); let treasury = Treasury::try_from_bytes(&treasury_data)?; let treasury_bump = treasury.bump as u8; diff --git a/src/state/config.rs b/src/state/config.rs index 2020ac3..b796b69 100644 --- a/src/state/config.rs +++ b/src/state/config.rs @@ -19,6 +19,9 @@ pub struct Config { /// The base reward rate paid out for a hash of minimum difficulty. pub base_reward_rate: u64, + /// The timestamp of the last reset + pub last_reset_at: i64, + /// The minimum accepted difficulty. pub min_difficulty: u32, diff --git a/src/state/treasury.rs b/src/state/treasury.rs index 3ae7bc2..0975de6 100644 --- a/src/state/treasury.rs +++ b/src/state/treasury.rs @@ -12,6 +12,7 @@ use crate::{ #[derive(Clone, Copy, Debug, PartialEq, Pod, ShankAccount, Zeroable)] pub struct Treasury { /// The bump of the treasury account PDA, for signing CPIs. + // TODO Is this needed if bump is const? pub bump: u64, }