diff --git a/src/consts.rs b/src/consts.rs new file mode 100644 index 0000000..3f85837 --- /dev/null +++ b/src/consts.rs @@ -0,0 +1,78 @@ +use solana_program::{keccak::Hash, pubkey, pubkey::Pubkey}; + +// TODO Set this before deployment +/// The unix timestamp after which mining is allowed. +pub const START_AT: i64 = 0; + +// SHA2 const stable +/// Bus pubkeys +pub const BUS_ADDRESSES: [Pubkey; BUS_COUNT] = [ + pubkey!("2uwqyH2gKqstgAFCSniirx73X4iQek5ETc2vVJKUiNMg"), + pubkey!("FRMC6jVczm1cRaEs5EhDsfw7X8vsmSDpf3bJWVkawngu"), + pubkey!("9nWyycs4GHjnLujPR2sbA1A8K8CkiLc5VzxWUD4hg2uM"), + pubkey!("Kt7kqD3MyvxLbj4ek9urXUxkDoxaMuQn82K2VdYD1jM"), + pubkey!("8r9mXYnFQXhwrNfvatGUTxbbNSqxScuCwp4sBTSxDVTJ"), + pubkey!("D9cEH32k8p9uWc4w5RrStK9rWssU8NuX1Dg5YaUim4wL"), + pubkey!("H1RKMYADPzd4C1j1RZu51NvRSVktoTYEJyeVy98Kmdyu"), + pubkey!("3XbdZNbBjjp8qnDJjv1RxaKisyfx6ahznYkSigs6dayy"), +]; + +/// The mint address of the ORE token. +pub const MINT_ADDRESS: Pubkey = pubkey!("DY4JVebraRXg9BGt4MRU4mvqHGDzmi2Ay1HGjDU5YeNf"); + +/// Treasury address +pub const TREASURY_ADDRESS: Pubkey = pubkey!("67PLJej6iZm915WbEu6NLeZtRZtnHc5nSVQvkHRZyPiC"); + +/// The initial reward rate to payout in the first epoch. +pub const INITIAL_REWARD_RATE: u64 = 10u64.pow(3u32); + +/// The initial hashing difficulty. The admin authority can update this in the future, if needed. +pub const INITIAL_DIFFICULTY: Hash = Hash::new_from_array([ + 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, 255, +]); + +/// 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 +pub const TOKEN_DECIMALS: u8 = 9; + +/// One ORE token, denominated in units of nanoORE. +pub const ONE_ORE: u64 = 10u64.pow(TOKEN_DECIMALS as u32); + +/// The duration of an epoch, in units of seconds. +pub const EPOCH_DURATION: i64 = 60; + +/// The target quantity of ORE to be mined per epoch, in units of nanoORE. +/// Inflation rate ≈ 1 ORE / epoch (min 0, max 2) +pub const TARGET_EPOCH_REWARDS: u64 = ONE_ORE; + +/// The maximum quantity of ORE that can be mined per epoch, in units of nanoORE. +pub const MAX_EPOCH_REWARDS: u64 = ONE_ORE.saturating_mul(2); + +/// The quantity of ORE each bus is allowed to issue per epoch. +pub const BUS_EPOCH_REWARDS: u64 = MAX_EPOCH_REWARDS.saturating_div(BUS_COUNT as u64); + +/// The number of bus accounts, for parallelizing mine operations. +pub const BUS_COUNT: usize = 8; + +/// The smoothing factor for reward rate changes. The reward rate cannot change by more or less +/// than factor of this constant from one epoch to the next. +pub const SMOOTHING_FACTOR: u64 = 2; + +// Assert MAX_EPOCH_REWARDS is evenly divisible by BUS_COUNT. +static_assertions::const_assert!( + (MAX_EPOCH_REWARDS / BUS_COUNT as u64) * BUS_COUNT as u64 == MAX_EPOCH_REWARDS +); + +/// The seed of the bus account PDA. +pub const BUS: &[u8] = b"bus"; + +/// The seed of the mint account PDA. +pub const MINT: &[u8] = b"mint"; + +/// The seed of the proof account PDA. +pub const PROOF: &[u8] = b"proof"; + +/// The seed of the treasury account PDA. +pub const TREASURY: &[u8] = b"treasury"; diff --git a/src/instruction.rs b/src/instruction.rs index 2c6307c..94f9955 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -36,7 +36,7 @@ pub enum OreInstruction { #[account(1, name = "signer", desc = "Signer", signer)] #[account(2, name = "proof", desc = "Ore miner proof account", writable)] #[account(3, name = "system_program", desc = "Solana system program")] - CreateProof = 1, + Register = 1, #[account(0, name = "ore_program", desc = "Ore program")] #[account(1, name = "signer", desc = "Signer", signer)] @@ -107,7 +107,7 @@ pub struct InitializeArgs { #[repr(C)] #[derive(Clone, Copy, Debug, Pod, Zeroable)] -pub struct CreateProofArgs { +pub struct RegisterArgs { pub bump: u8, } @@ -137,14 +137,14 @@ pub struct UpdateDifficultyArgs { } impl_to_bytes!(InitializeArgs); -impl_to_bytes!(CreateProofArgs); +impl_to_bytes!(RegisterArgs); impl_to_bytes!(MineArgs); impl_to_bytes!(ClaimArgs); impl_to_bytes!(UpdateAdminArgs); impl_to_bytes!(UpdateDifficultyArgs); impl_instruction_from_bytes!(InitializeArgs); -impl_instruction_from_bytes!(CreateProofArgs); +impl_instruction_from_bytes!(RegisterArgs); impl_instruction_from_bytes!(MineArgs); impl_instruction_from_bytes!(ClaimArgs); impl_instruction_from_bytes!(UpdateAdminArgs); @@ -199,16 +199,20 @@ pub fn mine(signer: Pubkey, bus: Pubkey, hash: Hash, nonce: u64) -> Instruction } } -pub fn create_proof(signer: Pubkey) -> Instruction { - let proof = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &crate::id()).0; +pub fn register(signer: Pubkey) -> Instruction { + let proof_pda = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &crate::id()); Instruction { program_id: crate::id(), accounts: vec![ AccountMeta::new(signer, true), - AccountMeta::new(proof, false), + AccountMeta::new(proof_pda.0, false), AccountMeta::new_readonly(solana_program::system_program::id(), false), ], - data: OreInstruction::CreateProof.to_vec(), + data: [ + OreInstruction::Register.to_vec(), + RegisterArgs { bump: proof_pda.1 }.to_bytes().to_vec(), + ] + .concat(), } } diff --git a/src/lib.rs b/src/lib.rs index 806019b..3abbb89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +pub mod consts; pub mod error; pub mod instruction; mod loaders; @@ -5,14 +6,14 @@ mod processor; pub mod state; pub mod utils; +pub use consts::*; +use instruction::*; use processor::*; use solana_program::{ - self, account_info::AccountInfo, declare_id, entrypoint::ProgramResult, keccak::Hash, - program_error::ProgramError, pubkey, pubkey::Pubkey, + self, account_info::AccountInfo, declare_id, entrypoint::ProgramResult, log::sol_log, + program_error::ProgramError, pubkey::Pubkey, }; -use instruction::*; - // TODO Test admin and difficulty adjustment functions // TODO Increase decimals? @@ -21,97 +22,23 @@ declare_id!("CeJShZEAzBLwtcLQvbZc7UT38e4nUTn63Za5UFyYYDTS"); #[cfg(not(feature = "no-entrypoint"))] solana_program::entrypoint!(process_instruction); -// TODO Set this before deployment -/// The unix timestamp after which mining is allowed. -pub const START_AT: i64 = 0; - -/// The initial reward rate to payout in the first epoch. -pub const INITIAL_REWARD_RATE: u64 = 10u64.pow(3u32); - -/// The initial hashing difficulty. The admin authority can update this in the future, if needed. -pub const INITIAL_DIFFICULTY: Hash = Hash::new_from_array([ - 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, 255, -]); - -/// The mint address of the ORE token. -pub const MINT_ADDRESS: Pubkey = pubkey!("DY4JVebraRXg9BGt4MRU4mvqHGDzmi2Ay1HGjDU5YeNf"); - -/// 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 -pub const TOKEN_DECIMALS: u8 = 9; - -/// One ORE token, denominated in units of nanoORE. -pub const ONE_ORE: u64 = 10u64.pow(TOKEN_DECIMALS as u32); - -/// The duration of an epoch, in units of seconds. -pub const EPOCH_DURATION: i64 = 60; - -/// The target quantity of ORE to be mined per epoch, in units of nanoORE. -/// Inflation rate ≈ 1 ORE / epoch (min 0, max 2) -pub const TARGET_EPOCH_REWARDS: u64 = ONE_ORE; - -/// The maximum quantity of ORE that can be mined per epoch, in units of nanoORE. -pub const MAX_EPOCH_REWARDS: u64 = ONE_ORE.saturating_mul(2); - -/// The quantity of ORE each bus is allowed to issue per epoch. -pub const BUS_EPOCH_REWARDS: u64 = MAX_EPOCH_REWARDS.saturating_div(BUS_COUNT as u64); - -/// The number of bus accounts, for parallelizing mine operations. -pub const BUS_COUNT: usize = 8; - -/// The smoothing factor for reward rate changes. The reward rate cannot change by more or less -/// than factor of this constant from one epoch to the next. -pub const SMOOTHING_FACTOR: u64 = 2; - -// Assert MAX_EPOCH_REWARDS is evenly divisible by BUS_COUNT. -static_assertions::const_assert!( - (MAX_EPOCH_REWARDS / BUS_COUNT as u64) * BUS_COUNT as u64 == MAX_EPOCH_REWARDS -); - -/// The seed of the bus account PDA. -pub const BUS: &[u8] = b"bus"; - -/// The seed of the mint account PDA. -pub const MINT: &[u8] = b"mint"; - -/// The seed of the proof account PDA. -pub const PROOF: &[u8] = b"proof"; - -/// The seed of the treasury account PDA. -pub const TREASURY: &[u8] = b"treasury"; - -/// Treasury address -pub const TREASURY_ADDRESS: Pubkey = pubkey!("67PLJej6iZm915WbEu6NLeZtRZtnHc5nSVQvkHRZyPiC"); - -// SHA2 const stable -/// Bus pubkeys -pub const BUS_ADDRESSES: [Pubkey; 8] = [ - pubkey!("2uwqyH2gKqstgAFCSniirx73X4iQek5ETc2vVJKUiNMg"), - pubkey!("FRMC6jVczm1cRaEs5EhDsfw7X8vsmSDpf3bJWVkawngu"), - pubkey!("9nWyycs4GHjnLujPR2sbA1A8K8CkiLc5VzxWUD4hg2uM"), - pubkey!("Kt7kqD3MyvxLbj4ek9urXUxkDoxaMuQn82K2VdYD1jM"), - pubkey!("8r9mXYnFQXhwrNfvatGUTxbbNSqxScuCwp4sBTSxDVTJ"), - pubkey!("D9cEH32k8p9uWc4w5RrStK9rWssU8NuX1Dg5YaUim4wL"), - pubkey!("H1RKMYADPzd4C1j1RZu51NvRSVktoTYEJyeVy98Kmdyu"), - pubkey!("3XbdZNbBjjp8qnDJjv1RxaKisyfx6ahznYkSigs6dayy"), -]; - /// Processes the incoming instruction pub fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], data: &[u8], ) -> ProgramResult { + sol_log("1"); let (tag, data) = data .split_first() .ok_or(ProgramError::InvalidInstructionData)?; + sol_log(format!("2: {:?}", tag).as_str()); let ix = OreInstruction::try_from(*tag).or(Err(ProgramError::InvalidInstructionData))?; + sol_log(format!("3: {:?}", ix).as_str()); match ix { OreInstruction::Reset => process_reset(program_id, accounts, data)?, - OreInstruction::CreateProof => process_create_proof(program_id, accounts, data)?, + OreInstruction::Register => process_register(program_id, accounts, data)?, OreInstruction::Mine => process_mine(program_id, accounts, data)?, OreInstruction::Claim => process_claim(program_id, accounts, data)?, OreInstruction::Initialize => process_initialize(program_id, accounts, data)?, diff --git a/src/processor/mod.rs b/src/processor/mod.rs index ebd658b..532584e 100644 --- a/src/processor/mod.rs +++ b/src/processor/mod.rs @@ -1,15 +1,15 @@ mod claim; -mod create_proof; mod initialize; mod mine; +mod register; mod reset; mod update_admin; mod update_difficulty; pub use claim::*; -pub use create_proof::*; pub use initialize::*; pub use mine::*; +pub use register::*; pub use reset::*; pub use update_admin::*; pub use update_difficulty::*; diff --git a/src/processor/create_proof.rs b/src/processor/register.rs similarity index 91% rename from src/processor/create_proof.rs rename to src/processor/register.rs index 0cac262..abdeca3 100644 --- a/src/processor/create_proof.rs +++ b/src/processor/register.rs @@ -6,7 +6,7 @@ use solana_program::{ }; use crate::{ - instruction::CreateProofArgs, + instruction::RegisterArgs, loaders::*, state::Proof, utils::AccountDeserialize, @@ -14,13 +14,13 @@ use crate::{ PROOF, }; -pub fn process_create_proof<'a, 'info>( +pub fn process_register<'a, 'info>( _program_id: &Pubkey, accounts: &'a [AccountInfo<'info>], data: &[u8], ) -> ProgramResult { // Parse args - let args = CreateProofArgs::try_from_bytes(data)?; + let args = RegisterArgs::try_from_bytes(data)?; // Load accounts let [signer, proof_info, system_program] = accounts else { diff --git a/tests/test_mine.rs b/tests/test_mine.rs index 11b65e6..9b73116 100644 --- a/tests/test_mine.rs +++ b/tests/test_mine.rs @@ -1,7 +1,6 @@ use std::str::FromStr; use ore::{ - instruction::{CreateProofArgs, MineArgs, OreInstruction}, state::{Proof, Treasury}, utils::AccountDeserialize, BUS, PROOF, TREASURY, @@ -9,10 +8,9 @@ use ore::{ use solana_program::{ clock::Clock, epoch_schedule::DEFAULT_SLOTS_PER_EPOCH, - instruction::{AccountMeta, Instruction}, keccak::{hashv, Hash as KeccakHash}, pubkey::Pubkey, - system_program, sysvar, + sysvar, }; use solana_program_test::{processor, BanksClient, ProgramTest}; use solana_sdk::{ @@ -25,21 +23,9 @@ async fn test_mine() { // Setup let (mut banks, payer, hash) = setup_program_test_env().await; - // Build proof ix + // Build register ix let proof_pda = Pubkey::find_program_address(&[PROOF, payer.pubkey().as_ref()], &ore::id()); - let ix_0 = Instruction { - program_id: ore::id(), - accounts: vec![ - AccountMeta::new(payer.pubkey(), true), - AccountMeta::new(proof_pda.0, false), - AccountMeta::new_readonly(system_program::id(), false), - ], - data: [ - OreInstruction::CreateProof.to_vec(), - CreateProofArgs { bump: proof_pda.1 }.to_bytes().to_vec(), - ] - .concat(), - }; + let ix_0 = ore::instruction::register(payer.pubkey()); // Submit tx let tx = Transaction::new_signed_with_payer(&[ix_0], Some(&payer.pubkey()), &[&payer], hash); @@ -65,29 +51,7 @@ async fn test_mine() { // Build mine ix let bus_pda = Pubkey::find_program_address(&[BUS, &[0]], &ore::id()); - let treasury_pda = Pubkey::find_program_address(&[TREASURY], &ore::id()); - let ix_1 = Instruction { - program_id: ore::id(), - accounts: vec![ - AccountMeta::new(payer.pubkey(), true), - AccountMeta::new(bus_pda.0, false), - AccountMeta::new(proof_pda.0, false), - AccountMeta::new_readonly(treasury_pda.0, false), - // AccountMeta::new(treasury_pda.0, false), - // AccountMeta::new(proof_pda.0, false), - AccountMeta::new_readonly(sysvar::slot_hashes::id(), false), - ], - data: [ - OreInstruction::Mine.to_vec(), - MineArgs { - hash: next_hash.into(), - nonce: nonce.to_le_bytes(), - } - .to_bytes() - .to_vec(), - ] - .concat(), - }; + let ix_1 = ore::instruction::mine(payer.pubkey(), bus_pda.0, next_hash.into(), nonce); // Submit tx let tx = Transaction::new_signed_with_payer(&[ix_1], Some(&payer.pubkey()), &[&payer], hash); diff --git a/tests/test_reset.rs b/tests/test_reset.rs index 501b7bb..3a8ab68 100644 --- a/tests/test_reset.rs +++ b/tests/test_reset.rs @@ -1,21 +1,14 @@ use std::str::FromStr; use ore::{ - instruction::OreInstruction, state::{Bus, Treasury}, utils::AccountDeserialize, BUS, BUS_COUNT, BUS_EPOCH_REWARDS, INITIAL_DIFFICULTY, INITIAL_REWARD_RATE, MAX_EPOCH_REWARDS, MINT, TREASURY, }; use solana_program::{ - clock::Clock, - epoch_schedule::DEFAULT_SLOTS_PER_EPOCH, - hash::Hash, - instruction::{AccountMeta, Instruction}, - program_option::COption, - program_pack::Pack, - pubkey::Pubkey, - sysvar, + clock::Clock, epoch_schedule::DEFAULT_SLOTS_PER_EPOCH, hash::Hash, program_option::COption, + program_pack::Pack, pubkey::Pubkey, sysvar, }; use solana_program_test::{processor, BanksClient, ProgramTest}; use solana_sdk::{ @@ -45,28 +38,8 @@ async fn test_reset() { let treasury_tokens_address = spl_associated_token_account::get_associated_token_address(&treasury_pda.0, &mint_pda.0); - // Build ix - let ix = Instruction { - program_id: ore::ID, - accounts: vec![ - AccountMeta::new(payer.pubkey(), true), - AccountMeta::new(bus_pdas[0].0, false), - AccountMeta::new(bus_pdas[1].0, false), - AccountMeta::new(bus_pdas[2].0, false), - AccountMeta::new(bus_pdas[3].0, false), - AccountMeta::new(bus_pdas[4].0, false), - AccountMeta::new(bus_pdas[5].0, false), - AccountMeta::new(bus_pdas[6].0, false), - AccountMeta::new(bus_pdas[7].0, false), - AccountMeta::new(mint_pda.0, false), - AccountMeta::new(treasury_pda.0, false), - AccountMeta::new(treasury_tokens_address, false), - AccountMeta::new_readonly(spl_token::id(), false), - ], - data: [OreInstruction::Reset.to_vec()].concat(), - }; - // Submit tx + let ix = ore::instruction::reset(payer.pubkey()); let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], hash); let res = banks.process_transaction(tx).await; assert!(res.is_ok());