use serde::{Deserialize, Serialize};
use steel::*;
use crate::state::{round_pda, OreAccountV4};
use super::OreAccountV1;
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable, Serialize, Deserialize)]
pub struct RoundV1 {
pub id: u64,
pub deployed: [u64; 25],
pub slot_hash: [u8; 32],
pub count: [u64; 25],
pub expires_at: u64,
pub motherlode: u64,
pub rent_payer: Pubkey,
pub top_miner: Pubkey,
pub top_miner_reward: u64,
pub total_deployed: u64,
pub total_miners: u64,
pub total_vaulted: u64,
pub total_winnings: u64,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable, Serialize, Deserialize)]
pub struct RoundV4 {
pub id: u64,
pub sol: [u64; 25],
pub mass: [u64; 25],
pub miners: [u64; 25],
pub entropy: [u8; 32],
pub closes_at: u64,
pub motherlode: u64,
pub rent_payer: Pubkey,
pub rewards: [u64; 25],
pub protocol_fee: u64,
pub unique_miners: u64,
pub winner: Pubkey,
}
impl RoundV1 {
pub fn pda(&self) -> (Pubkey, u8) {
round_pda(self.id)
}
pub fn rng(&self) -> Option<u64> {
if self.slot_hash == [0; 32] || self.slot_hash == [u8::MAX; 32] {
return None;
}
let r1 = u64::from_le_bytes(self.slot_hash[0..8].try_into().unwrap());
let r2 = u64::from_le_bytes(self.slot_hash[8..16].try_into().unwrap());
let r3 = u64::from_le_bytes(self.slot_hash[16..24].try_into().unwrap());
let r4 = u64::from_le_bytes(self.slot_hash[24..32].try_into().unwrap());
let r = r1 ^ r2 ^ r3 ^ r4;
Some(r)
}
pub fn winning_square(&self, rng: u64) -> usize {
(rng % 25) as usize
}
pub fn top_miner_sample(&self, rng: u64, winning_square: usize) -> u64 {
if self.deployed[winning_square] == 0 {
return 0;
}
rng.reverse_bits() % self.deployed[winning_square]
}
pub fn calculate_total_winnings(&self, winning_square: usize) -> u64 {
let mut total_winnings = 0;
for (i, &deployed) in self.deployed.iter().enumerate() {
if i != winning_square {
total_winnings += deployed;
}
}
total_winnings
}
pub fn is_split_reward(&self, rng: u64) -> bool {
let rng = rng.reverse_bits().to_le_bytes();
let r1 = u16::from_le_bytes(rng[0..2].try_into().unwrap());
let r2 = u16::from_le_bytes(rng[2..4].try_into().unwrap());
let r3 = u16::from_le_bytes(rng[4..6].try_into().unwrap());
let r4 = u16::from_le_bytes(rng[6..8].try_into().unwrap());
let r = r1 ^ r2 ^ r3 ^ r4;
r % 2 == 0
}
pub fn did_hit_motherlode(&self, rng: u64) -> bool {
rng.reverse_bits() % 625 == 0
}
}
impl RoundV4 {
pub fn pda(&self) -> (Pubkey, u8) {
round_pda(self.id)
}
pub fn rng(&self) -> Option<u64> {
if self.entropy == [0; 32] || self.entropy == [u8::MAX; 32] {
return None;
}
let r1 = u64::from_le_bytes(self.entropy[0..8].try_into().unwrap());
let r2 = u64::from_le_bytes(self.entropy[8..16].try_into().unwrap());
let r3 = u64::from_le_bytes(self.entropy[16..24].try_into().unwrap());
let r4 = u64::from_le_bytes(self.entropy[24..32].try_into().unwrap());
let r = r1 ^ r2 ^ r3 ^ r4;
Some(r)
}
pub fn winning_square(&self, rng: u64) -> usize {
(rng % 25) as usize
}
pub fn top_miner_sample(&self, rng: u64, winning_square: usize) -> u64 {
if self.sol[winning_square] == 0 {
return 0;
}
rng.reverse_bits() % self.sol[winning_square]
}
pub fn calculate_total_winnings(&self, winning_square: usize) -> u64 {
let mut total_winnings = 0;
for (i, &sol) in self.sol.iter().enumerate() {
if i != winning_square {
total_winnings += sol;
}
}
total_winnings
}
pub fn is_split_reward(&self, rng: u64) -> bool {
let rng = rng.reverse_bits().to_le_bytes();
let r1 = u16::from_le_bytes(rng[0..2].try_into().unwrap());
let r2 = u16::from_le_bytes(rng[2..4].try_into().unwrap());
let r3 = u16::from_le_bytes(rng[4..6].try_into().unwrap());
let r4 = u16::from_le_bytes(rng[6..8].try_into().unwrap());
let r = r1 ^ r2 ^ r3 ^ r4;
r % 2 == 0
}
pub fn did_hit_motherlode(&self, rng: u64) -> bool {
rng.reverse_bits() % 625 == 0
}
}
account!(OreAccountV1, RoundV1);
account!(OreAccountV4, RoundV4);
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub enum Round {
V1(RoundV1),
V4(RoundV4),
}
impl Round {
pub fn id(&self) -> u64 {
match self {
Round::V1(r) => r.id,
Round::V4(r) => r.id,
}
}
pub fn deployed(&self) -> [u64; 25] {
match self {
Round::V1(r) => r.deployed,
Round::V4(r) => r.sol,
}
}
pub fn slot_hash(&self) -> [u8; 32] {
match self {
Round::V1(r) => r.slot_hash,
Round::V4(r) => r.entropy,
}
}
pub fn count(&self) -> [u64; 25] {
match self {
Round::V1(r) => r.count,
Round::V4(r) => r.miners,
}
}
pub fn expires_at(&self) -> u64 {
match self {
Round::V1(r) => r.expires_at,
Round::V4(r) => r.closes_at,
}
}
pub fn motherlode(&self) -> u64 {
match self {
Round::V1(r) => r.motherlode,
Round::V4(r) => r.motherlode,
}
}
pub fn rent_payer(&self) -> Pubkey {
match self {
Round::V1(r) => r.rent_payer,
Round::V4(r) => r.rent_payer,
}
}
pub fn top_miner(&self) -> Pubkey {
match self {
Round::V1(r) => r.top_miner,
Round::V4(r) => r.winner,
}
}
pub fn top_miner_reward(&self) -> u64 {
match self {
Round::V1(r) => r.top_miner_reward,
Round::V4(_) => 0,
}
}
pub fn total_deployed(&self) -> u64 {
match self {
Round::V1(r) => r.total_deployed,
Round::V4(r) => r.sol.iter().sum(),
}
}
pub fn total_miners(&self) -> u64 {
match self {
Round::V1(r) => r.total_miners,
Round::V4(r) => r.unique_miners,
}
}
pub fn total_vaulted(&self) -> u64 {
match self {
Round::V1(r) => r.total_vaulted,
Round::V4(_) => 0,
}
}
pub fn total_winnings(&self) -> u64 {
match self {
Round::V1(r) => r.total_winnings,
Round::V4(_) => 0,
}
}
pub fn pda(&self) -> (Pubkey, u8) {
match self {
Round::V1(r) => r.pda(),
Round::V4(r) => r.pda(),
}
}
pub fn rng(&self) -> Option<u64> {
match self {
Round::V1(r) => r.rng(),
Round::V4(r) => r.rng(),
}
}
pub fn winning_square(&self, rng: u64) -> usize {
match self {
Round::V1(r) => r.winning_square(rng),
Round::V4(r) => r.winning_square(rng),
}
}
pub fn top_miner_sample(&self, rng: u64, winning_square: usize) -> u64 {
match self {
Round::V1(r) => r.top_miner_sample(rng, winning_square),
Round::V4(r) => r.top_miner_sample(rng, winning_square),
}
}
pub fn calculate_total_winnings(&self, winning_square: usize) -> u64 {
match self {
Round::V1(r) => r.calculate_total_winnings(winning_square),
Round::V4(r) => r.calculate_total_winnings(winning_square),
}
}
pub fn is_split_reward(&self, rng: u64) -> bool {
match self {
Round::V1(r) => r.is_split_reward(rng),
Round::V4(r) => r.is_split_reward(rng),
}
}
pub fn did_hit_motherlode(&self, rng: u64) -> bool {
match self {
Round::V1(r) => r.did_hit_motherlode(rng),
Round::V4(r) => r.did_hit_motherlode(rng),
}
}
}