diff --git a/Cargo.lock b/Cargo.lock index 1dd4c24..2b1dd2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2607,6 +2607,7 @@ dependencies = [ "spl-token", "static_assertions", "thiserror", + "utils", ] [[package]] @@ -2624,6 +2625,7 @@ dependencies = [ "spl-associated-token-account", "spl-token", "tokio", + "utils", ] [[package]] @@ -5722,6 +5724,14 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utils" +version = "2.0.0" +dependencies = [ + "bytemuck", + "solana-program", +] + [[package]] name = "valuable" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 2b46f9e..2e1a7ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["core/*"] +members = ["core/*", "utils"] [workspace.package] version = "2.0.0" @@ -13,8 +13,10 @@ readme = "./README.md" keywords = ["solana", "crypto", "mining"] [workspace.dependencies] +bytemuck = "1.14.3" drillx = { git = "https://github.com/regolith-labs/drillx", branch = "master", features = ["solana"] } mpl-token-metadata = "4.1.2" solana-program = "1.18" spl-token = { version = "^4", features = ["no-entrypoint"] } spl-associated-token-account = { version = "^2.2", features = [ "no-entrypoint" ] } +utils = { path = "utils" } diff --git a/core/api/Cargo.toml b/core/api/Cargo.toml index 9477a8c..e8b69b1 100644 --- a/core/api/Cargo.toml +++ b/core/api/Cargo.toml @@ -22,4 +22,5 @@ solana-program.workspace = true spl-token.workspace = true spl-associated-token-account.workspace = true static_assertions = "1.1.0" -thiserror = "1.0.57" \ No newline at end of file +thiserror = "1.0.57" +utils.workspace = true \ No newline at end of file diff --git a/core/api/src/event.rs b/core/api/src/event.rs new file mode 100644 index 0000000..675e9e9 --- /dev/null +++ b/core/api/src/event.rs @@ -0,0 +1,13 @@ +use bytemuck::{Pod, Zeroable}; + +use crate::utils::impl_to_bytes; + +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] +pub struct MineEvent { + pub difficulty: u64, + pub reward: u64, + pub timing: i64, +} + +impl_to_bytes!(MineEvent); diff --git a/core/api/src/instruction.rs b/core/api/src/instruction.rs index f87371f..5d00d43 100644 --- a/core/api/src/instruction.rs +++ b/core/api/src/instruction.rs @@ -8,7 +8,10 @@ use solana_program::{ system_program, sysvar, }; -use crate::{consts::*, impl_instruction_from_bytes, impl_to_bytes}; +use crate::{ + consts::*, + utils::{impl_instruction_from_bytes, impl_to_bytes}, +}; #[repr(u8)] #[derive(Clone, Copy, Debug, Eq, PartialEq, ShankInstruction, TryFromPrimitive)] diff --git a/core/api/src/lib.rs b/core/api/src/lib.rs index 85782b2..409cafb 100644 --- a/core/api/src/lib.rs +++ b/core/api/src/lib.rs @@ -1,8 +1,10 @@ pub mod consts; pub mod error; +pub mod event; pub mod instruction; pub mod state; -pub mod utils; + +pub(crate) use utils; use solana_program::declare_id; diff --git a/core/api/src/state/bus.rs b/core/api/src/state/bus.rs index 7275119..2eaa557 100644 --- a/core/api/src/state/bus.rs +++ b/core/api/src/state/bus.rs @@ -1,10 +1,9 @@ use bytemuck::{Pod, Zeroable}; use shank::ShankAccount; -use crate::{ - impl_account_from_bytes, impl_to_bytes, - utils::{AccountDiscriminator, Discriminator}, -}; +use crate::utils::{impl_account_from_bytes, impl_to_bytes, Discriminator}; + +use super::AccountDiscriminator; /// Bus accounts are responsible for distributing mining rewards. /// There are 8 busses total to minimize write-lock contention and allow for parallel mine operations. @@ -23,8 +22,8 @@ pub struct Bus { } impl Discriminator for Bus { - fn discriminator() -> AccountDiscriminator { - AccountDiscriminator::Bus + fn discriminator() -> u8 { + AccountDiscriminator::Bus.into() } } diff --git a/core/api/src/state/config.rs b/core/api/src/state/config.rs index 2c8214f..d08e00d 100644 --- a/core/api/src/state/config.rs +++ b/core/api/src/state/config.rs @@ -2,10 +2,9 @@ use bytemuck::{Pod, Zeroable}; use shank::ShankAccount; use solana_program::pubkey::Pubkey; -use crate::{ - impl_account_from_bytes, impl_to_bytes, - utils::{AccountDiscriminator, Discriminator}, -}; +use crate::utils::{impl_account_from_bytes, impl_to_bytes, Discriminator}; + +use super::AccountDiscriminator; /// Config is a singleton account which manages admin configurable variables. #[repr(C)] @@ -28,8 +27,8 @@ pub struct Config { } impl Discriminator for Config { - fn discriminator() -> AccountDiscriminator { - AccountDiscriminator::Config + fn discriminator() -> u8 { + AccountDiscriminator::Config.into() } } diff --git a/core/api/src/state/mod.rs b/core/api/src/state/mod.rs index 7a3b009..e228cac 100644 --- a/core/api/src/state/mod.rs +++ b/core/api/src/state/mod.rs @@ -7,3 +7,14 @@ pub use bus::*; pub use config::*; pub use proof::*; pub use treasury::*; + +use num_enum::{IntoPrimitive, TryFromPrimitive}; + +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] +pub enum AccountDiscriminator { + Bus = 100, + Config = 101, + Proof = 102, + Treasury = 103, +} diff --git a/core/api/src/state/proof.rs b/core/api/src/state/proof.rs index 1d1aa76..83e9dd5 100644 --- a/core/api/src/state/proof.rs +++ b/core/api/src/state/proof.rs @@ -2,10 +2,9 @@ use bytemuck::{Pod, Zeroable}; use shank::ShankAccount; use solana_program::pubkey::Pubkey; -use crate::{ - impl_account_from_bytes, impl_to_bytes, - utils::{AccountDiscriminator, Discriminator}, -}; +use crate::utils::{impl_account_from_bytes, impl_to_bytes, Discriminator}; + +use super::AccountDiscriminator; /// Proof accounts track a miner's current hash, claimable rewards, and lifetime stats. /// Every miner is allowed one proof account which is required by the program to mine or claim rewards. @@ -41,8 +40,8 @@ pub struct Proof { } impl Discriminator for Proof { - fn discriminator() -> AccountDiscriminator { - AccountDiscriminator::Proof + fn discriminator() -> u8 { + AccountDiscriminator::Proof.into() } } diff --git a/core/api/src/state/treasury.rs b/core/api/src/state/treasury.rs index e699ae2..5b78b6c 100644 --- a/core/api/src/state/treasury.rs +++ b/core/api/src/state/treasury.rs @@ -1,10 +1,9 @@ use bytemuck::{Pod, Zeroable}; use shank::ShankAccount; -use crate::{ - impl_account_from_bytes, impl_to_bytes, - utils::{AccountDiscriminator, Discriminator}, -}; +use crate::utils::{impl_account_from_bytes, impl_to_bytes, Discriminator}; + +use super::AccountDiscriminator; /// Treasury is a singleton account which manages all program wide variables. /// It is the mint authority for the Ore token and also the authority of the program-owned token account. @@ -13,8 +12,8 @@ use crate::{ pub struct Treasury {} impl Discriminator for Treasury { - fn discriminator() -> AccountDiscriminator { - AccountDiscriminator::Treasury + fn discriminator() -> u8 { + AccountDiscriminator::Treasury.into() } } diff --git a/core/program/Cargo.toml b/core/program/Cargo.toml index 3ea6d1c..cb97a8e 100644 --- a/core/program/Cargo.toml +++ b/core/program/Cargo.toml @@ -25,6 +25,7 @@ ore-api = { path = "../api" } solana-program.workspace = true spl-token.workspace = true spl-associated-token-account.workspace = true +utils.workspace = true [dev-dependencies] bs64 = "0.1.2" diff --git a/core/program/src/lib.rs b/core/program/src/lib.rs index 2fcd002..010e69c 100644 --- a/core/program/src/lib.rs +++ b/core/program/src/lib.rs @@ -8,6 +8,8 @@ use solana_program::{ pubkey::Pubkey, }; +pub(crate) use utils; + #[cfg(not(feature = "no-entrypoint"))] solana_program::entrypoint!(process_instruction); diff --git a/core/program/src/loaders.rs b/core/program/src/loaders.rs index 61cc800..1daaa96 100644 --- a/core/program/src/loaders.rs +++ b/core/program/src/loaders.rs @@ -1,7 +1,6 @@ use ore_api::{ consts::*, state::{Bus, Config, Proof, Treasury}, - utils::{AccountDeserialize, Discriminator}, }; use solana_program::{ account_info::AccountInfo, program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, @@ -9,6 +8,8 @@ use solana_program::{ }; use spl_token::state::Mint; +use crate::utils::{AccountDeserialize, Discriminator}; + /// Errors if: /// - Account is not a signer. pub fn load_signer<'a, 'info>(info: &'a AccountInfo<'info>) -> Result<(), ProgramError> { diff --git a/core/program/src/processor/claim.rs b/core/program/src/processor/claim.rs index 7a688d2..554f824 100644 --- a/core/program/src/processor/claim.rs +++ b/core/program/src/processor/claim.rs @@ -1,12 +1,10 @@ -use ore_api::{ - consts::*, error::OreError, instruction::ClaimArgs, state::Proof, utils::AccountDeserialize, -}; +use ore_api::{consts::*, error::OreError, instruction::ClaimArgs, state::Proof}; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey, }; -use crate::loaders::*; +use crate::{loaders::*, utils::AccountDeserialize}; /// Claim distributes Ore from the treasury to a miner. Its responsibilies include: /// 1. Decrement the miner's claimable balance. diff --git a/core/program/src/processor/close.rs b/core/program/src/processor/close.rs index 4f6d0f6..107f1c0 100644 --- a/core/program/src/processor/close.rs +++ b/core/program/src/processor/close.rs @@ -1,10 +1,10 @@ -use ore_api::{state::Proof, utils::AccountDeserialize}; +use ore_api::state::Proof; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey, system_program, }; -use crate::loaders::*; +use crate::{loaders::*, utils::AccountDeserialize}; /// Close closes a proof account and returns the rent to the owner. Its responsibilities include: /// 1. Realloc proof account size to 0. diff --git a/core/program/src/processor/crown.rs b/core/program/src/processor/crown.rs index 9a2975d..aeb1827 100644 --- a/core/program/src/processor/crown.rs +++ b/core/program/src/processor/crown.rs @@ -1,13 +1,10 @@ -use ore_api::{ - state::{Config, Proof}, - utils::AccountDeserialize, -}; +use ore_api::state::{Config, Proof}; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey, }; -use crate::loaders::*; +use crate::{loaders::*, utils::AccountDeserialize}; /// Crown flags an account as the top staker if their balance is greater than the last known top staker. pub fn process_crown<'a, 'info>( diff --git a/core/program/src/processor/initialize.rs b/core/program/src/processor/initialize.rs index d01110e..d4200f9 100644 --- a/core/program/src/processor/initialize.rs +++ b/core/program/src/processor/initialize.rs @@ -4,9 +4,6 @@ use ore_api::{ consts::*, instruction::*, state::{Bus, Config, Treasury}, - utils::create_pda, - utils::AccountDeserialize, - utils::Discriminator, }; use solana_program::{ account_info::AccountInfo, @@ -18,7 +15,10 @@ use solana_program::{ }; use spl_token::state::Mint; -use crate::loaders::*; +use crate::{ + loaders::*, + utils::{create_pda, AccountDeserialize, Discriminator}, +}; /// Initialize sets up the Ore program. Its responsibilities include: /// 1. Initialize the 8 bus accounts. diff --git a/core/program/src/processor/mine.rs b/core/program/src/processor/mine.rs index 20c0778..d362ed0 100644 --- a/core/program/src/processor/mine.rs +++ b/core/program/src/processor/mine.rs @@ -4,9 +4,9 @@ use drillx::Solution; use ore_api::{ consts::*, error::OreError, + event::MineEvent, instruction::{MineArgs, OreInstruction}, state::{Bus, Config, Proof}, - utils::{AccountDeserialize, MineEvent}, }; use solana_program::program::set_return_data; #[allow(deprecated)] @@ -25,7 +25,7 @@ use solana_program::{ sysvar::{self, instructions::load_current_index, Sysvar}, }; -use crate::loaders::*; +use crate::{loaders::*, utils::AccountDeserialize}; /// Mine is the primary workhorse instruction of the Ore program. Its responsibilities include: /// 1. Calculate the hash from the provided nonce. diff --git a/core/program/src/processor/open.rs b/core/program/src/processor/open.rs index 782ceab..66e603a 100644 --- a/core/program/src/processor/open.rs +++ b/core/program/src/processor/open.rs @@ -1,11 +1,6 @@ use std::mem::size_of; -use ore_api::{ - consts::*, - instruction::OpenArgs, - state::Proof, - utils::{create_pda, AccountDeserialize, Discriminator}, -}; +use ore_api::{consts::*, instruction::OpenArgs, state::Proof}; use solana_program::{ account_info::AccountInfo, blake3::hashv, @@ -18,7 +13,10 @@ use solana_program::{ sysvar::{self, Sysvar}, }; -use crate::loaders::*; +use crate::{ + loaders::*, + utils::{create_pda, AccountDeserialize, Discriminator}, +}; /// Register generates a new hash chain for a prospective miner. Its responsibilities include: /// 1. Initialize a new proof account. diff --git a/core/program/src/processor/reset.rs b/core/program/src/processor/reset.rs index ccc1528..dd656a3 100644 --- a/core/program/src/processor/reset.rs +++ b/core/program/src/processor/reset.rs @@ -2,7 +2,6 @@ use ore_api::{ consts::*, error::OreError, state::{Bus, Config}, - utils::AccountDeserialize, }; use solana_program::{ account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, @@ -10,8 +9,12 @@ use solana_program::{ }; use spl_token::state::Mint; -use crate::loaders::{ - load_bus, load_config, load_mint, load_program, load_signer, load_token_account, load_treasury, +use crate::{ + loaders::{ + load_bus, load_config, load_mint, load_program, load_signer, load_token_account, + load_treasury, + }, + utils::AccountDeserialize, }; /// Reset sets up the Ore program for the next epoch. Its responsibilities include: @@ -165,9 +168,9 @@ pub(crate) fn calculate_new_reward_rate(current_rate: u64, epoch_rewards: u64) - mod tests { use rand::{distributions::Uniform, Rng}; - use crate::{ - calculate_new_reward_rate, BUS_EPOCH_REWARDS, MAX_EPOCH_REWARDS, SMOOTHING_FACTOR, - TARGET_EPOCH_REWARDS, + use crate::calculate_new_reward_rate; + use ore_api::consts::{ + BUS_EPOCH_REWARDS, MAX_EPOCH_REWARDS, SMOOTHING_FACTOR, TARGET_EPOCH_REWARDS, }; const FUZZ_SIZE: u64 = 10_000; diff --git a/core/program/src/processor/stake.rs b/core/program/src/processor/stake.rs index e948060..d72ddb3 100644 --- a/core/program/src/processor/stake.rs +++ b/core/program/src/processor/stake.rs @@ -1,10 +1,10 @@ -use ore_api::{consts::*, instruction::StakeArgs, state::Proof, utils::AccountDeserialize}; +use ore_api::{consts::*, instruction::StakeArgs, state::Proof}; use solana_program::{ account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey, sysvar::Sysvar, }; -use crate::loaders::*; +use crate::{loaders::*, utils::AccountDeserialize}; /// Stake deposits Ore into a miner's proof account to earn multiplier. Its responsibilies include: /// 1. Transfer tokens from the miner to the treasury account. diff --git a/core/program/src/processor/update.rs b/core/program/src/processor/update.rs index ed5313e..35f384c 100644 --- a/core/program/src/processor/update.rs +++ b/core/program/src/processor/update.rs @@ -1,10 +1,10 @@ -use ore_api::{state::Proof, utils::AccountDeserialize}; +use ore_api::state::Proof; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey, }; -use crate::loaders::*; +use crate::{loaders::*, utils::AccountDeserialize}; /// Update changes the miner authority on a proof account. pub fn process_update<'a, 'info>( diff --git a/stake/api/src/lib.rs b/stake/api/src/lib.rs new file mode 100644 index 0000000..e69de29 diff --git a/stake/program/src/lib.rs b/stake/program/src/lib.rs new file mode 100644 index 0000000..e69de29 diff --git a/utils/Cargo.toml b/utils/Cargo.toml new file mode 100644 index 0000000..cc44d0f --- /dev/null +++ b/utils/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "utils" +description = "Utils for building ORE programs" +version.workspace = true +edition.workspace = true +license.workspace = true +homepage.workspace = true +documentation.workspace = true +repository.workspace = true +keywords.workspace = true + +[lib] +crate-type = ["cdylib", "lib"] +name = "utils" + +[dependencies] +bytemuck.workspace = true +solana-program.workspace = true diff --git a/core/api/src/utils.rs b/utils/src/lib.rs similarity index 87% rename from core/api/src/utils.rs rename to utils/src/lib.rs index 669c7d9..1694c98 100644 --- a/core/api/src/utils.rs +++ b/utils/src/lib.rs @@ -1,5 +1,3 @@ -use bytemuck::{Pod, Zeroable}; -use num_enum::{IntoPrimitive, TryFromPrimitive}; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey, rent::Rent, sysvar::Sysvar, @@ -73,17 +71,8 @@ pub fn create_pda<'a, 'info>( Ok(()) } -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] -pub enum AccountDiscriminator { - Bus = 100, - Config = 101, - Proof = 102, - Treasury = 103, -} - pub trait Discriminator { - fn discriminator() -> AccountDiscriminator; + fn discriminator() -> u8; //AccountDiscriminator; } pub trait AccountDeserialize { @@ -109,7 +98,7 @@ macro_rules! impl_account_from_bytes { fn try_from_bytes( data: &[u8], ) -> Result<&Self, solana_program::program_error::ProgramError> { - if (Self::discriminator() as u8).ne(&data[0]) { + if Self::discriminator().ne(&data[0]) { return Err(solana_program::program_error::ProgramError::InvalidAccountData); } bytemuck::try_from_bytes::(&data[8..]).or(Err( @@ -119,7 +108,7 @@ macro_rules! impl_account_from_bytes { fn try_from_bytes_mut( data: &mut [u8], ) -> Result<&mut Self, solana_program::program_error::ProgramError> { - if (Self::discriminator() as u8).ne(&data[0]) { + if Self::discriminator().ne(&data[0]) { return Err(solana_program::program_error::ProgramError::InvalidAccountData); } bytemuck::try_from_bytes_mut::(&mut data[8..]).or(Err( @@ -144,13 +133,3 @@ macro_rules! impl_instruction_from_bytes { } }; } - -#[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] -pub struct MineEvent { - pub difficulty: u64, - pub reward: u64, - pub timing: i64, -} - -impl_to_bytes!(MineEvent);