From 418738127ca02828c5e2c2498cca257c335e5ae9 Mon Sep 17 00:00:00 2001 From: Hardhat Chad Date: Wed, 14 Feb 2024 00:15:46 +0000 Subject: [PATCH] cu optimization --- src/lib.rs | 17 ++++---- src/loaders.rs | 38 +++++++++-------- src/processor/epoch.rs | 88 ++++++++++++++++++++++++--------------- src/processor/mine.rs | 93 ++++++++++++++++++------------------------ tests/test_mine.rs | 33 +++++---------- 5 files changed, 133 insertions(+), 136 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index de3f032..3e5c9eb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -109,16 +109,13 @@ pub fn process_instruction( .ok_or(ProgramError::InvalidInstructionData)?; let ix = OreInstruction::try_from(*tag).or(Err(ProgramError::InvalidInstructionData))?; - // if ix.eq(&OreInstruction::Proof) { - // process_proof(program_id, accounts, data)? - // } - // match ix { - // OreInstruction::Epoch => process_epoch(program_id, accounts, data)?, - // OreInstruction::Proof => process_proof(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)?, - // } + match ix { + OreInstruction::Epoch => process_epoch(program_id, accounts, data)?, + OreInstruction::Proof => process_proof(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)?, + } Ok(()) } diff --git a/src/loaders.rs b/src/loaders.rs index a11d3db..59f20bb 100644 --- a/src/loaders.rs +++ b/src/loaders.rs @@ -1,6 +1,6 @@ use solana_program::{ - account_info::AccountInfo, program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, - syscalls, system_program, + account_info::AccountInfo, program_error::ProgramError, program_memory::sol_memcmp, + program_pack::Pack, pubkey::Pubkey, system_program, }; use spl_token::state::Mint; @@ -23,7 +23,7 @@ pub fn load_uninitialized_pda<'a, 'info>( seeds: &[&[u8]], ) -> Result<&'a AccountInfo<'info>, ProgramError> { let key = Pubkey::create_program_address(seeds, &crate::id())?; - if !info.key.eq(&key) { + if sol_memcmp(info.key.as_ref(), key.as_ref(), 32) != 0 { return Err(ProgramError::InvalidSeeds); } load_uninitialized_account(info) @@ -32,7 +32,7 @@ pub fn load_uninitialized_pda<'a, 'info>( pub fn load_bus<'a, 'info>( info: &'a AccountInfo<'info>, ) -> Result<&'a AccountInfo<'info>, ProgramError> { - if !info.owner.eq(&crate::id()) { + if sol_memcmp(info.owner.as_ref(), crate::id().as_ref(), 32) != 0 { return Err(ProgramError::InvalidAccountOwner); } if info.data_is_empty() { @@ -53,7 +53,7 @@ pub fn load_proof<'a, 'info>( info: &'a AccountInfo<'info>, signer: &Pubkey, ) -> Result<&'a AccountInfo<'info>, ProgramError> { - if !info.owner.eq(&crate::id()) { + if sol_memcmp(info.owner.as_ref(), crate::id().as_ref(), 32) != 0 { return Err(ProgramError::InvalidAccountOwner); } if info.data_is_empty() { @@ -63,7 +63,8 @@ pub fn load_proof<'a, 'info>( let proof_data = info.data.borrow(); let proof = bytemuck::try_from_bytes::(&proof_data).unwrap(); - if !proof.authority.eq(&signer) { + // if !proof.authority.eq(&signer) { + if sol_memcmp(proof.authority.as_ref(), signer.as_ref(), 32) != 0 { return Err(ProgramError::InvalidAccountData); } @@ -73,14 +74,14 @@ pub fn load_proof<'a, 'info>( pub fn load_treasury<'a, 'info>( info: &'a AccountInfo<'info>, ) -> Result<&'a AccountInfo<'info>, ProgramError> { - if !info.owner.eq(&crate::id()) { + if sol_memcmp(info.owner.as_ref(), crate::id().as_ref(), 32) != 0 { return Err(ProgramError::InvalidAccountOwner); } if info.data_is_empty() { return Err(ProgramError::UninitializedAccount); } - if !info.key.eq(&TREASURY_ADDRESS) { + if sol_memcmp(info.key.as_ref(), TREASURY_ADDRESS.as_ref(), 32) != 0 { return Err(ProgramError::InvalidSeeds); } @@ -90,7 +91,7 @@ pub fn load_treasury<'a, 'info>( pub fn load_mint<'a, 'info>( info: &'a AccountInfo<'info>, ) -> Result<&'a AccountInfo<'info>, ProgramError> { - if !info.owner.eq(&spl_token::id()) { + if sol_memcmp(info.owner.as_ref(), spl_token::id().as_ref(), 32) != 0 { return Err(ProgramError::InvalidAccountOwner); } if info.data_is_empty() { @@ -102,7 +103,7 @@ pub fn load_mint<'a, 'info>( return Err(ProgramError::InvalidAccountData); } - if !info.key.eq(&MINT_ADDRESS) { + if sol_memcmp(info.key.as_ref(), MINT_ADDRESS.as_ref(), 32) != 0 { return Err(ProgramError::InvalidAccountData); } @@ -114,7 +115,7 @@ pub fn load_token_account<'a, 'info>( owner: &Pubkey, mint: &Pubkey, ) -> Result<&'a AccountInfo<'info>, ProgramError> { - if !info.owner.eq(&spl_token::id()) { + if sol_memcmp(info.owner.as_ref(), spl_token::id().as_ref(), 32) != 0 { return Err(ProgramError::InvalidAccountOwner); } if info.data_is_empty() { @@ -125,10 +126,10 @@ pub fn load_token_account<'a, 'info>( let account = spl_token::state::Account::unpack_unchecked(&account_data) .or(Err(ProgramError::InvalidAccountData))?; - if !account.mint.eq(mint) { + if sol_memcmp(account.mint.as_ref(), mint.as_ref(), 32) != 0 { return Err(ProgramError::InvalidAccountData); } - if !account.owner.eq(owner) { + if sol_memcmp(account.owner.as_ref(), owner.as_ref(), 32) != 0 { return Err(ProgramError::InvalidAccountData); } @@ -138,12 +139,15 @@ pub fn load_token_account<'a, 'info>( pub fn load_uninitialized_account<'a, 'info>( info: &'a AccountInfo<'info>, ) -> Result<&'a AccountInfo<'info>, ProgramError> { + if sol_memcmp(info.owner.as_ref(), system_program::id().as_ref(), 32) != 0 { + return Err(ProgramError::AccountAlreadyInitialized); + } + if !info.data_is_empty() { + return Err(ProgramError::AccountAlreadyInitialized); + } if !info.is_writable { return Err(ProgramError::InvalidAccountData); } - if !info.data_is_empty() || !info.owner.eq(&system_program::id()) { - return Err(ProgramError::AccountAlreadyInitialized); - } Ok(info) } @@ -151,7 +155,7 @@ pub fn load_account<'a, 'info>( info: &'a AccountInfo<'info>, key: Pubkey, ) -> Result<&'a AccountInfo<'info>, ProgramError> { - if !info.key.eq(&key) { + if sol_memcmp(info.key.as_ref(), key.as_ref(), 32) != 0 { return Err(ProgramError::InvalidAccountData); } Ok(info) diff --git a/src/processor/epoch.rs b/src/processor/epoch.rs index 85e9e03..a99caa0 100644 --- a/src/processor/epoch.rs +++ b/src/processor/epoch.rs @@ -1,10 +1,6 @@ use solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Clock, - entrypoint::ProgramResult, - program_error::ProgramError, - pubkey::Pubkey, - sysvar::Sysvar, + account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, + program_error::ProgramError, pubkey::Pubkey, sysvar::Sysvar, }; use crate::{ @@ -19,38 +15,66 @@ pub fn process_epoch<'a, 'info>( accounts: &'a [AccountInfo<'info>], _data: &[u8], ) -> ProgramResult { - let accounts_iter = &mut accounts.iter(); + 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); + }; + let _ = load_signer(signer)?; + let _ = load_bus(bus_0_info)?; + let _ = load_bus(bus_1_info)?; + let _ = load_bus(bus_2_info)?; + let _ = load_bus(bus_3_info)?; + let _ = load_bus(bus_4_info)?; + let _ = load_bus(bus_5_info)?; + let _ = load_bus(bus_6_info)?; + let _ = load_bus(bus_7_info)?; + let _ = load_mint(mint_info)?; + let _ = load_treasury(treasury_info)?; + let _ = load_token_account(treasury_tokens_info, treasury_info.key, mint_info.key)?; + let _ = load_account(token_program, spl_token::id())?; - // Account 1: Signer - let _signer = load_signer(next_account_info(accounts_iter)?)?; - - // Accounts 2-9: Busses - let busses = vec![ - load_bus(next_account_info(accounts_iter)?)?, - load_bus(next_account_info(accounts_iter)?)?, - load_bus(next_account_info(accounts_iter)?)?, - load_bus(next_account_info(accounts_iter)?)?, - load_bus(next_account_info(accounts_iter)?)?, - load_bus(next_account_info(accounts_iter)?)?, - load_bus(next_account_info(accounts_iter)?)?, - load_bus(next_account_info(accounts_iter)?)?, + let busses: [&AccountInfo; 8] = [ + bus_0_info, bus_1_info, bus_2_info, bus_3_info, bus_4_info, bus_5_info, bus_6_info, + bus_7_info, ]; + // let _ = load_signer(signer)?; + // let _ = load_bus(bus_info)?; + // let _ = load_proof(proof_info, signer.key)?; + // let _ = load_treasury(treasury_info)?; + // let _ = load_account(slot_hashes_info, sysvar::slot_hashes::id())?; + + // let accounts_iter = &mut accounts.iter(); + + // Account 1: Signer + // let _signer = load_signer(next_account_info(accounts_iter)?)?; + + // Accounts 2-9: Busses + // let busses = vec![ + // load_bus(next_account_info(accounts_iter)?)?, + // load_bus(next_account_info(accounts_iter)?)?, + // load_bus(next_account_info(accounts_iter)?)?, + // load_bus(next_account_info(accounts_iter)?)?, + // load_bus(next_account_info(accounts_iter)?)?, + // load_bus(next_account_info(accounts_iter)?)?, + // load_bus(next_account_info(accounts_iter)?)?, + // load_bus(next_account_info(accounts_iter)?)?, + // ]; + // Account 10: Mint - let mint = load_mint(next_account_info(accounts_iter)?)?; + // let mint = load_mint(next_account_info(accounts_iter)?)?; // Account 11: Treasury - let treasury_info = load_treasury(next_account_info(accounts_iter)?)?; + // let treasury_info = load_treasury(next_account_info(accounts_iter)?)?; // Account 12: Treasury tokens - let treasury_tokens = load_token_account( - next_account_info(accounts_iter)?, - treasury_info.key, - mint.key, - )?; + // let treasury_tokens = load_token_account( + // next_account_info(accounts_iter)?, + // treasury_info.key, + // mint.key, + // )?; // Account 13: Token program - let token_program = load_account(next_account_info(accounts_iter)?, spl_token::id())?; + // let token_program = load_account(next_account_info(accounts_iter)?, spl_token::id())?; // Validate epoch has ended let clock = Clock::get().unwrap(); @@ -81,16 +105,16 @@ pub fn process_epoch<'a, 'info>( solana_program::program::invoke_signed( &spl_token::instruction::mint_to( &spl_token::id(), - mint.key, - treasury_tokens.key, + mint_info.key, + treasury_tokens_info.key, treasury_info.key, &[treasury_info.key], total_epoch_rewards, )?, &[ token_program.clone(), - mint.clone(), - treasury_tokens.clone(), + mint_info.clone(), + treasury_tokens_info.clone(), treasury_info.clone(), ], &[&[TREASURY, &[treasury_bump]]], diff --git a/src/processor/mine.rs b/src/processor/mine.rs index b3b1ad4..d95712f 100644 --- a/src/processor/mine.rs +++ b/src/processor/mine.rs @@ -23,71 +23,56 @@ pub fn process_mine<'a, 'info>( accounts: &'a [AccountInfo<'info>], data: &[u8], ) -> ProgramResult { - // let accounts_iter = &mut accounts.iter(); - // let args = - // bytemuck::try_from_bytes::(data).or(Err(ProgramError::InvalidInstructionData))?; + // Parse args + let args = + bytemuck::try_from_bytes::(data).or(Err(ProgramError::InvalidInstructionData))?; - // let [signer, bus_info, proof_info, treasury_info, slot_hashes_info] = accounts else { - // return Err(ProgramError::NotEnoughAccountKeys); - // }; - // let _ = load_signer(signer)?; - // let _ = load_bus(bus_info)?; - // let _ = load_proof(proof_info, signer.key)?; - // let _ = load_treasury(treasury_info)?; - // let _ = load_account(slot_hashes_info, sysvar::slot_hashes::id())?; - - // Account 1: Signer - // let signer = load_signer(next_account_info(accounts_iter)?)?; - - // Account 2: Bus - // let bus_info = load_bus(next_account_info(accounts_iter)?)?; - - // Account 3: Proof - // let proof_info = load_proof(next_account_info(accounts_iter)?, signer.key)?; - - // Account 4: Treasury - // let treasury_info = load_treasury(next_account_info(accounts_iter)?)?; - - // Account 5: Slot hashes svsvar - // let slot_hashes_info = - // load_account(next_account_info(accounts_iter)?, sysvar::slot_hashes::id())?; + // Parse accounts + let [signer, bus_info, proof_info, treasury_info, slot_hashes_info] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + let _ = load_signer(signer)?; + let _ = load_bus(bus_info)?; + let _ = load_proof(proof_info, signer.key)?; + let _ = load_treasury(treasury_info)?; + let _ = load_account(slot_hashes_info, sysvar::slot_hashes::id())?; // Validate epoch is active - // let clock = Clock::get().unwrap(); - // let treasury_data = treasury_info.data.borrow(); - // let treasury = bytemuck::try_from_bytes::(&treasury_data).unwrap(); - // let epoch_end_at = treasury.epoch_start_at.saturating_add(EPOCH_DURATION); - // if !clock.unix_timestamp.lt(&epoch_end_at) { - // return Err(ProgramError::Custom(1)); - // } + let clock = Clock::get().unwrap(); + let treasury_data = treasury_info.data.borrow(); + let treasury = bytemuck::try_from_bytes::(&treasury_data).unwrap(); + let epoch_end_at = treasury.epoch_start_at.saturating_add(EPOCH_DURATION); + if !clock.unix_timestamp.lt(&epoch_end_at) { + return Err(ProgramError::Custom(1)); + } // Validate provided hash - // let mut proof_data = proof_info.data.borrow_mut(); - // let mut proof = bytemuck::try_from_bytes_mut::(&mut proof_data).unwrap(); - // validate_hash( - // proof.hash.into(), - // args.hash.into(), - // *signer.key, - // u64::from_le_bytes(args.nonce), - // treasury.difficulty.into(), - // )?; + let mut proof_data = proof_info.data.borrow_mut(); + let mut proof = bytemuck::try_from_bytes_mut::(&mut proof_data).unwrap(); + validate_hash( + proof.hash.into(), + args.hash.into(), + *signer.key, + u64::from_le_bytes(args.nonce), + treasury.difficulty.into(), + )?; // Update claimable rewards - // let mut bus_data = bus_info.data.borrow_mut(); - // let mut bus = bytemuck::try_from_bytes_mut::(&mut bus_data).unwrap(); - // if !bus.available_rewards.ge(&treasury.reward_rate) { - // return Err(ProgramError::Custom(1)); - // } - // bus.available_rewards = bus.available_rewards.saturating_sub(treasury.reward_rate); - // proof.claimable_rewards = proof.claimable_rewards.saturating_add(treasury.reward_rate); + let mut bus_data = bus_info.data.borrow_mut(); + let mut bus = bytemuck::try_from_bytes_mut::(&mut bus_data).unwrap(); + if bus.available_rewards.lt(&treasury.reward_rate) { + return Err(ProgramError::Custom(1)); + } + bus.available_rewards = bus.available_rewards.saturating_sub(treasury.reward_rate); + proof.claimable_rewards = proof.claimable_rewards.saturating_add(treasury.reward_rate); // Hash most recent slot hash into the next challenge to prevent pre-mining attacks - // let slot_hash_bytes = &slot_hashes_info.data.borrow()[0..size_of::()]; - // proof.hash = hashv(&[KeccakHash::from(args.hash).as_ref(), slot_hash_bytes]).into(); + let slot_hash_bytes = &slot_hashes_info.data.borrow()[0..size_of::()]; + proof.hash = hashv(&[KeccakHash::from(args.hash).as_ref(), slot_hash_bytes]).into(); // Update lifetime stats - // proof.total_hashes = proof.total_hashes.saturating_add(1); - // proof.total_rewards = proof.total_rewards.saturating_add(1); + proof.total_hashes = proof.total_hashes.saturating_add(1); + proof.total_rewards = proof.total_rewards.saturating_add(1); // TODO Log? diff --git a/tests/test_mine.rs b/tests/test_mine.rs index 66e2f45..1e53af9 100644 --- a/tests/test_mine.rs +++ b/tests/test_mine.rs @@ -46,9 +46,9 @@ async fn test_mine() { assert!(res.is_ok()); // Assert proof state - // let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); - // assert_eq!(proof_account.owner, ore::id()); - // let proof = bytemuck::try_from_bytes::(&proof_account.data).unwrap(); + let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); + assert_eq!(proof_account.owner, ore::id()); + let proof = bytemuck::try_from_bytes::(&proof_account.data).unwrap(); // Assert proof state let treasury_pda = Pubkey::find_program_address(&[TREASURY], &ore::id()); @@ -56,22 +56,11 @@ async fn test_mine() { let treasury = bytemuck::try_from_bytes::(&treasury_account.data).unwrap(); // Find next hash - // let (next_hash, nonce) = find_next_hash( - // proof.hash.into(), - // treasury.difficulty.into(), - // payer.pubkey(), - // ); - - // println!("Hash: {:?}", next_hash); - // println!("None: {:?}", nonce); - // let args = MineArgs { - // hash: next_hash.into(), - // nonce, - // }; - // let bytes = args.to_bytes(); - // let parsed_args = bytemuck::try_from_bytes::(bytes); - // println!("Args: {:?}", args.to_bytes()); - // assert!(parsed_args.is_ok()); + let (next_hash, nonce) = find_next_hash( + proof.hash.into(), + treasury.difficulty.into(), + payer.pubkey(), + ); // Build mine ix let bus_pda = Pubkey::find_program_address(&[BUS, &[0]], &ore::id()); @@ -88,10 +77,8 @@ async fn test_mine() { data: [ OreInstruction::Mine.to_vec(), MineArgs { - // hash: next_hash.into(), - // nonce: nonce.to_le_bytes(), - hash: KeccakHash::new_unique().into(), - nonce: 42u64.to_le_bytes(), + hash: next_hash.into(), + nonce: nonce.to_le_bytes(), } .to_bytes() .to_vec(),