From b3c4f205d8aaeb9340ae0857ccb9ce56094e4b32 Mon Sep 17 00:00:00 2001 From: Hardhat Chad Date: Mon, 9 Jun 2025 10:35:53 -0700 Subject: [PATCH] min diff --- cli/src/main.rs | 9 ++--- ore/api/src/consts.rs | 10 ++++-- ore/api/src/state/block.rs | 19 +++++----- ore/api/src/state/miner.rs | 3 ++ ore/program/src/close.rs | 16 +-------- ore/program/src/mine.rs | 73 ++++++++++++++++++++++++++++++-------- ore/program/src/open.rs | 7 ++-- 7 files changed, 90 insertions(+), 47 deletions(-) diff --git a/cli/src/main.rs b/cli/src/main.rs index 83aa06c..f21b1e3 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -87,13 +87,14 @@ fn print_block(block: Block) { println!("Address: {:?}", address); println!(" Id: {:?}", block.id); println!(" Start slot: {:?}", block.start_slot); - println!(" Best miner: {:?}", block.best_miner); println!( - " Reward: {:?}", - amount_to_ui_amount(block.reward, TOKEN_DECIMALS) + " Reward rate: {:?}", + amount_to_ui_amount(block.reward_rate, TOKEN_DECIMALS) ); println!(" Slot hash: {:?}", block.slot_hash); - println!(" Best hash: {:?}\n", block.best_hash); + println!(" Min difficulty: {:?}", block.min_difficulty); + println!(" Total hashes: {:?}", block.total_hashes); + println!(" Winning hashes: {:?}", block.winning_hashes); } async fn log_blocks(rpc: &RpcClient) -> Result<(), anyhow::Error> { diff --git a/ore/api/src/consts.rs b/ore/api/src/consts.rs index fe773ae..ad72f13 100644 --- a/ore/api/src/consts.rs +++ b/ore/api/src/consts.rs @@ -62,7 +62,13 @@ pub const SLOT_WINDOW: u64 = 4; pub const HASH_TOKEN_SUPPLY: u64 = 10_000_000; /// The block reward. -pub const BLOCK_REWARD: u64 = ONE_ORE * 10; +// pub const BLOCK_REWARD: u64 = ONE_ORE * 10; /// The virtual ORE liquidity. -pub const VIRTUAL_ORE_LIQUIDITY: u64 = BLOCK_REWARD / 2; +pub const VIRTUAL_ORE_LIQUIDITY: u64 = ONE_ORE * 5; + +/// The minimum difficulty required for payout. +pub const MIN_DIFFICULTY: u64 = 10; + +/// The reward rate per satisfying hash (0.002048 ORE). +pub const REWARD_RATE: u64 = 204_800_000; diff --git a/ore/api/src/state/block.rs b/ore/api/src/state/block.rs index 612b286..a65a4c3 100644 --- a/ore/api/src/state/block.rs +++ b/ore/api/src/state/block.rs @@ -7,17 +7,14 @@ use super::OreAccount; #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] pub struct Block { - /// The best hash. - pub best_hash: [u8; 32], - - /// The miner who submitted the best hash. - pub best_miner: Pubkey, - /// The block number. pub id: u64, - /// The amount of ORE to payout to the miner who submitted the best hash. - pub reward: u64, + /// The minimum difficulty required for payout. + pub min_difficulty: u64, + + /// The reward rate per satisfying hash. + pub reward_rate: u64, /// The hash of the starting slot. pub slot_hash: [u8; 32], @@ -27,6 +24,12 @@ pub struct Block { /// The total number of hashes submitted to the block. pub total_hashes: u64, + + /// The total amount of rewards paid out to miners. + pub total_rewards: u64, + + /// The total number of hashes submitted to the block. + pub winning_hashes: u64, } impl Block { diff --git a/ore/api/src/state/miner.rs b/ore/api/src/state/miner.rs index e6558eb..db9bdc5 100644 --- a/ore/api/src/state/miner.rs +++ b/ore/api/src/state/miner.rs @@ -21,6 +21,9 @@ pub struct Miner { /// The amount of ORE this miner has mined. pub total_rewards: u64, + + /// The number of winning hashes this miner has submitted. + pub winning_hashes: u64, } impl Miner { diff --git a/ore/program/src/close.rs b/ore/program/src/close.rs index 7bfd4cf..5b872d6 100644 --- a/ore/program/src/close.rs +++ b/ore/program/src/close.rs @@ -5,7 +5,7 @@ use steel::*; pub fn process_close(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult { // Load accounts. let clock = Clock::get()?; - let [signer_info, block_info, market_info, mint_base_info, mint_quote_info, recipient_info, treasury_info, vault_base_info, vault_quote_info, system_program, token_program] = + let [signer_info, block_info, market_info, mint_base_info, mint_quote_info, vault_base_info, vault_quote_info, system_program, token_program] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -19,7 +19,6 @@ pub fn process_close(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul .assert_mut(|m| m.id == block.id)?; mint_base_info.has_address(&market.base.mint)?.as_mint()?; mint_quote_info.has_address(&market.quote.mint)?.as_mint()?; - treasury_info.has_address(&TREASURY_ADDRESS)?; let vault_base = vault_base_info.as_associated_token_account(market_info.key, mint_base_info.key)?; let vault_quote = @@ -27,19 +26,6 @@ pub fn process_close(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul system_program.is_program(&system_program::ID)?; token_program.is_program(&spl_token::ID)?; - // Payout block reward. - if block.best_miner != Pubkey::default() { - recipient_info.as_associated_token_account(&block.best_miner, &MINT_ADDRESS)?; - mint_to_signed( - mint_quote_info, - recipient_info, - treasury_info, - token_program, - block.reward, - &[TREASURY], - )?; - } - // Burn base liquidity. burn_signed( vault_base_info, diff --git a/ore/program/src/mine.rs b/ore/program/src/mine.rs index e305c30..2860167 100644 --- a/ore/program/src/mine.rs +++ b/ore/program/src/mine.rs @@ -11,7 +11,7 @@ pub fn process_mine(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult // Load accounts. let clock = Clock::get()?; - let [signer_info, block_info, market_info, miner_info, mint_info, sender_info, system_program, token_program, slot_hashes_sysvar] = + let [signer_info, block_info, market_info, miner_info, mint_hash_info, mint_ore_info, recipient_info, sender_info, treasury_info, system_program, token_program, slot_hashes_sysvar] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -24,11 +24,16 @@ pub fn process_mine(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult let market = market_info .as_account::(&ore_api::ID)? .assert(|m| m.id == block.id)?; - mint_info.has_address(&market.base.mint)?.as_mint()?; + mint_hash_info.has_address(&market.base.mint)?.as_mint()?; + mint_ore_info.has_address(&MINT_ADDRESS)?.as_mint()?; + recipient_info + .is_writable()? + .as_associated_token_account(signer_info.key, &MINT_ADDRESS)?; sender_info .is_writable()? - .as_associated_token_account(signer_info.key, &mint_info.key)? + .as_associated_token_account(signer_info.key, &mint_hash_info.key)? .assert(|t| t.amount() >= amount)?; + treasury_info.has_address(&TREASURY_ADDRESS)?; system_program.is_program(&system_program::ID)?; token_program.is_program(&spl_token::ID)?; slot_hashes_sysvar.is_sysvar(&sysvar::slot_hashes::ID)?; @@ -55,18 +60,21 @@ pub fn process_mine(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult .assert_mut(|m| m.authority == *signer_info.key)? }; - // Update miner stats. - miner.total_hashes += amount; - // Burn hash tokens. - burn(sender_info, mint_info, signer_info, token_program, amount)?; + burn( + sender_info, + mint_hash_info, + signer_info, + token_program, + amount, + )?; // Set block slot hash. if block.slot_hash == [0; 32] { let slot_hashes = bincode::deserialize::(slot_hashes_sysvar.data.borrow().as_ref()).unwrap(); let Some(slot_hash) = slot_hashes.get(&block.start_slot) else { - // If mine is not called within 2.5 minutes of the block starting, + // If mine is not called within ~2.5 minutes of the block starting, // then the slot hash will be unavailable and secure hashes cannot be generated. return Ok(()); }; @@ -76,21 +84,56 @@ pub fn process_mine(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult // Reset miner hash if mining new block. if miner.block_id != block.id { miner.block_id = block.id; - let mut args = [0u8; 64]; - args[..32].copy_from_slice(&block.slot_hash); - args[32..].copy_from_slice(&miner.authority.to_bytes()); + let mut args = [0u8; 96]; + args[..32].copy_from_slice(&block.id.to_le_bytes()); + args[32..64].copy_from_slice(&block.slot_hash); + args[64..].copy_from_slice(&miner.authority.to_bytes()); miner.hash = hash(&args); } - // Mine. + // Mine and accumulate rewards. + let mut miner_reward = 0; for _ in 0..amount { + // Update stats block.total_hashes += 1; + miner.total_hashes += 1; + + // Generate hash. miner.hash = hash(miner.hash.as_ref()); - if miner.hash < block.best_hash { - block.best_hash = miner.hash; - block.best_miner = miner.authority; + + // Score and increment rewards. + let score = difficulty(miner.hash) as u64; + if score >= block.min_difficulty { + block.winning_hashes += 1; + miner.winning_hashes += 1; + miner_reward += block.reward_rate; } } + // Payout ORE. + block.total_rewards += miner_reward; + miner.total_rewards += miner_reward; + mint_to_signed( + mint_ore_info, + recipient_info, + treasury_info, + token_program, + miner_reward, + &[TREASURY], + )?; + Ok(()) } + +/// Returns the number of leading zeros on a 32 byte buffer. +pub fn difficulty(hash: [u8; 32]) -> u32 { + let mut count = 0; + for &byte in &hash { + let lz = byte.leading_zeros(); + count += lz; + if lz < 8 { + break; + } + } + count +} diff --git a/ore/program/src/open.rs b/ore/program/src/open.rs index a4fad1f..3f7bcde 100644 --- a/ore/program/src/open.rs +++ b/ore/program/src/open.rs @@ -52,12 +52,13 @@ pub fn process_open(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult &[BLOCK, &id.to_le_bytes()], )?; let block = block_info.as_account_mut::(&ore_api::ID)?; - block.best_hash = [0; 32]; - block.best_miner = Pubkey::default(); block.id = id; - block.reward = BLOCK_REWARD; + block.min_difficulty = MIN_DIFFICULTY; + block.reward_rate = REWARD_RATE; block.slot_hash = [0; 32]; block.start_slot = start_slot; + block.total_hashes = 0; + block.winning_hashes = 0; // Initialize market. create_program_account::(