diff --git a/api/src/consts.rs b/api/src/consts.rs index 2886be3..be53526 100644 --- a/api/src/consts.rs +++ b/api/src/consts.rs @@ -84,6 +84,9 @@ pub const MINT_ADDRESS: Pubkey = pubkey!("oreoU2P8bN6jkk3jbaiVxYnG1dCXcYxwhwyK9j /// The address of the sol mint account. pub const SOL_MINT: Pubkey = pubkey!("So11111111111111111111111111111111111111112"); +/// The address to indicate ORE rewards are split between all miners. +pub const SPLIT_ADDRESS: Pubkey = pubkey!("SpLiT11111111111111111111111111111111111112"); + /// The address of the treasury account. pub const TREASURY_ADDRESS: Pubkey = Pubkey::new_from_array(ed25519::derive_program_address(&[TREASURY], &PROGRAM_ID).0); diff --git a/api/src/state/board.rs b/api/src/state/board.rs index 9db5be5..7bf7f4f 100644 --- a/api/src/state/board.rs +++ b/api/src/state/board.rs @@ -1,6 +1,6 @@ use steel::*; -use crate::state::{board_pda, OreAccountOLD}; +use crate::state::board_pda; use super::OreAccount; @@ -17,40 +17,6 @@ pub struct Board { pub end_slot: u64, } -#[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] -pub struct BoardOLD { - /// The round number. - pub id: u64, - - /// The deployed SOL for the round. - pub deployed: [u64; 25], - - /// The timestamp at which the block starts mining. - pub start_at: i64, - - /// The slot at which the block starts trading. - pub start_slot: u64, - - /// The slot at which the block ends trading. - pub end_slot: u64, - - /// The hash of the end slot, provided by solana, used for random number generation. - pub slot_hash: [u8; 32], - - /// The top miner of the round. - pub top_miner: Pubkey, - - /// The total amount of SOL deployed in the round. - pub total_deployed: u64, - - /// The total amount of SOL put in the ORE vault. - pub total_vaulted: u64, - - /// The total amount of SOL won by miners for the round. - pub total_winnings: u64, -} - impl Board { pub fn pda(&self) -> (Pubkey, u8) { board_pda() @@ -58,4 +24,3 @@ impl Board { } account!(OreAccount, Board); -account!(OreAccountOLD, BoardOLD); diff --git a/api/src/state/miner.rs b/api/src/state/miner.rs index f53a346..95ff8c0 100644 --- a/api/src/state/miner.rs +++ b/api/src/state/miner.rs @@ -1,6 +1,6 @@ use steel::*; -use crate::state::{miner_pda, OreAccountOLD}; +use crate::state::miner_pda; use super::OreAccount; @@ -38,38 +38,6 @@ pub struct Miner { pub lifetime_rewards_ore: u64, } -#[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] -pub struct MinerOLD { - /// The authority of this miner account. - pub authority: Pubkey, - - /// The miner's prospects in the current round. - pub deployed: [u64; 25], - - /// Unused buffer. - #[deprecated(note = "No longer used")] - pub buffer: [u8; 32], - - /// The amount of SOL this miner has had refunded and may claim. - pub refund_sol: u64, - - /// The amount of SOL this miner can claim. - pub rewards_sol: u64, - - /// The amount of ORE this miner can claim. - pub rewards_ore: u64, - - /// The ID of the round this miner last played in. - pub round_id: u64, - - /// The total amount of SOL this miner has mined across all blocks. - pub lifetime_rewards_sol: u64, - - /// The total amount of ORE this miner has mined across all blocks. - pub lifetime_rewards_ore: u64, -} - impl Miner { pub fn pda(&self) -> (Pubkey, u8) { miner_pda(self.authority) @@ -77,4 +45,3 @@ impl Miner { } account!(OreAccount, Miner); -account!(OreAccountOLD, MinerOLD); diff --git a/api/src/state/mod.rs b/api/src/state/mod.rs index 80d903a..d8326c3 100644 --- a/api/src/state/mod.rs +++ b/api/src/state/mod.rs @@ -35,13 +35,6 @@ pub enum OreAccount { Round = 109, } -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] -pub enum OreAccountOLD { - MinerOLD = 103, - BoardOLD = 105, -} - pub fn automation_pda(authority: Pubkey) -> (Pubkey, u8) { Pubkey::find_program_address(&[AUTOMATION, &authority.to_bytes()], &crate::ID) } diff --git a/api/src/state/round.rs b/api/src/state/round.rs index 51a3323..49fd679 100644 --- a/api/src/state/round.rs +++ b/api/src/state/round.rs @@ -82,6 +82,17 @@ impl Round { total_winnings } + pub fn is_split_reward(&self, rng: u64) -> bool { + // One out of four rounds get split rewards. + let rng = rng.reverse_bits().to_le_bytes(); + let r1 = u64::from_le_bytes(rng[0..2].try_into().unwrap()); + let r2 = u64::from_le_bytes(rng[2..4].try_into().unwrap()); + let r3 = u64::from_le_bytes(rng[4..6].try_into().unwrap()); + let r4 = u64::from_le_bytes(rng[6..8].try_into().unwrap()); + let r = r1 ^ r2 ^ r3 ^ r4; + r % 4 == 0 + } + pub fn did_hit_motherlode(&self, rng: u64) -> bool { rng.reverse_bits() % 625 == 0 } diff --git a/cli/src/main.rs b/cli/src/main.rs index 9ed7210..ad4941b 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -636,11 +636,6 @@ async fn get_miners(rpc: &RpcClient) -> Result, anyhow::Err Ok(miners) } -async fn get_miners_old(rpc: &RpcClient) -> Result, anyhow::Error> { - let miners = get_program_accounts::(rpc, ore_api::ID, vec![]).await?; - Ok(miners) -} - async fn get_miners_participating( rpc: &RpcClient, round_id: u64, diff --git a/program/src/checkpoint.rs b/program/src/checkpoint.rs index b251a5e..c9bf40f 100644 --- a/program/src/checkpoint.rs +++ b/program/src/checkpoint.rs @@ -78,12 +78,20 @@ pub fn process_checkpoint(accounts: &[AccountInfo<'_>], _data: &[u8]) -> Program / round.deployed[winning_square] as u128) as u64; // Calculate ORE rewards. - let top_miner_sample = round.top_miner_sample(r, winning_square); - if top_miner_sample >= miner.cumulative[winning_square] - && top_miner_sample < miner.cumulative[winning_square] + miner.deployed[winning_square] - { - rewards_ore = round.top_miner_reward; - round.top_miner = miner.authority; + if round.top_miner == SPLIT_ADDRESS { + // If round is split, split the reward evenly among all miners. + rewards_ore = ((round.top_miner_reward * miner.deployed[winning_square]) + / round.deployed[winning_square]) as u64; + } else { + // If round is not split, payout to the top miner. + let top_miner_sample = round.top_miner_sample(r, winning_square); + if top_miner_sample >= miner.cumulative[winning_square] + && top_miner_sample + < miner.cumulative[winning_square] + miner.deployed[winning_square] + { + rewards_ore = round.top_miner_reward; + round.top_miner = miner.authority; + } } // Calculate motherlode rewards. diff --git a/program/src/reset.rs b/program/src/reset.rs index 711caf8..68d5111 100644 --- a/program/src/reset.rs +++ b/program/src/reset.rs @@ -1,5 +1,5 @@ use ore_api::prelude::*; -use solana_program::slot_hashes::SlotHashes; +use solana_program::{pubkey, slot_hashes::SlotHashes}; use steel::*; /// Pays out the winners and block reward. @@ -151,6 +151,11 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul &[TREASURY], )?; + // Set top miner to split reward address if the round is split. + if round.is_split_reward(r) { + round.top_miner = SPLIT_ADDRESS; + } + // Reset the motherlode if it was activated. if round.did_hit_motherlode(r) { round.motherlode = treasury.motherlode; @@ -193,7 +198,7 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul start_slot: board.start_slot, end_slot: board.end_slot, winning_square: winning_square as u64, - top_miner: Pubkey::default(), // top_miner.authority, + top_miner: round.top_miner, motherlode: round.motherlode, num_winners: round.count[winning_square], total_deployed: round.total_deployed,