clockwork_network/state/
rotator.rs1use {
2 super::Snapshot,
3 crate::state::SnapshotEntry,
4 anchor_lang::{prelude::*, AnchorDeserialize},
5 std::{
6 collections::hash_map::DefaultHasher,
7 convert::TryFrom,
8 hash::{Hash, Hasher},
9 },
10};
11
12pub const SEED_ROTATOR: &[u8] = b"rotator";
13
14#[account]
19#[derive(Debug)]
20pub struct Rotator {
21 pub last_rotation_at: u64, pub nonce: u64,
23 pub pool_pubkeys: Vec<Pubkey>,
24}
25
26impl Rotator {
27 pub fn pubkey() -> Pubkey {
28 Pubkey::find_program_address(&[SEED_ROTATOR], &crate::ID).0
29 }
30}
31
32impl TryFrom<Vec<u8>> for Rotator {
33 type Error = Error;
34 fn try_from(data: Vec<u8>) -> std::result::Result<Self, Self::Error> {
35 Rotator::try_deserialize(&mut data.as_slice())
36 }
37}
38
39pub trait RotatorAccount {
44 fn init(&mut self) -> Result<()>;
45
46 fn is_valid_entry(
47 &mut self,
48 entry: &Account<SnapshotEntry>,
49 snapshot: &Account<Snapshot>,
50 ) -> Result<bool>;
51
52 fn hash_nonce(&mut self) -> Result<()>;
53
54 fn add_pool(&mut self, pool: Pubkey) -> Result<()>;
55}
56
57impl RotatorAccount for Account<'_, Rotator> {
58 fn init(&mut self) -> Result<()> {
59 let mut hasher = DefaultHasher::new();
61 self.key().hash(&mut hasher);
62 self.nonce = hasher.finish();
63 self.last_rotation_at = 0;
64 self.pool_pubkeys = vec![];
65 Ok(())
66 }
67
68 fn is_valid_entry(
69 &mut self,
70 entry: &Account<SnapshotEntry>,
71 snapshot: &Account<Snapshot>,
72 ) -> Result<bool> {
73 match self.nonce.checked_rem(snapshot.stake_total) {
75 None => Ok(false),
76 Some(sample) => Ok(sample >= entry.stake_offset
77 && sample < entry.stake_offset.checked_add(entry.stake_amount).unwrap()),
78 }
79 }
80
81 fn hash_nonce(&mut self) -> Result<()> {
82 let mut hasher = DefaultHasher::new();
84 self.nonce.hash(&mut hasher);
85 self.nonce = hasher.finish();
86
87 self.last_rotation_at = Clock::get().unwrap().slot;
89 Ok(())
90 }
91
92 fn add_pool(&mut self, pool_pubkey: Pubkey) -> Result<()> {
93 self.pool_pubkeys.push(pool_pubkey);
95 Ok(())
96 }
97}