miclockwork_network_program/instructions/
pool_rotate.rs1use {
2 crate::{errors::*, state::*},
3 anchor_lang::prelude::*,
4};
5
6#[derive(Accounts)]
12pub struct PoolRotate<'info> {
13 #[account(address = Config::pubkey())]
14 pub config: Account<'info, Config>,
15
16 #[account(
17 mut,
18 seeds = [
19 SEED_POOL,
20 pool.id.to_be_bytes().as_ref(),
21 ],
22 bump,
23 )]
24 pub pool: Account<'info, Pool>,
25
26 #[account(address = Registry::pubkey())]
27 pub registry: Account<'info, Registry>,
28
29 #[account(mut)]
30 pub signatory: Signer<'info>,
31
32 #[account(
33 address = snapshot.pubkey(),
34 constraint = snapshot.id.eq(®istry.current_epoch)
35 )]
36 pub snapshot: Account<'info, Snapshot>,
37
38 #[account(
39 address = snapshot_frame.pubkey(),
40 has_one = snapshot,
41 has_one = worker
42 )]
43 pub snapshot_frame: Account<'info, SnapshotFrame>,
44
45 #[account(
46 address = worker.pubkey(),
47 has_one = signatory
48 )]
49 pub worker: Account<'info, Worker>,
50}
51
52pub fn handler(ctx: Context<PoolRotate>) -> Result<()> {
53 let pool = &mut ctx.accounts.pool;
55 let registry = &ctx.accounts.registry;
56 let snapshot = &ctx.accounts.snapshot;
57 let snapshot_frame = &ctx.accounts.snapshot_frame;
58 let worker = &ctx.accounts.worker;
59
60 require!(
62 pool.workers.len().lt(&pool.size)
63 || is_rotation_window_open(®istry, &snapshot, &snapshot_frame).unwrap(),
64 ClockworkError::PoolFull
65 );
66
67 require!(
69 !pool.workers.contains(&worker.key()),
70 ClockworkError::AlreadyInPool
71 );
72
73 pool.rotate(worker.key())?;
75
76 Ok(())
77}
78
79fn is_rotation_window_open(
80 registry: &Account<Registry>,
81 snapshot: &Account<Snapshot>,
82 snapshot_frame: &Account<SnapshotFrame>,
83) -> Result<bool> {
84 match registry.nonce.checked_rem(snapshot.total_stake) {
86 None => Ok(false),
87 Some(sample) => Ok(sample >= snapshot_frame.stake_offset
88 && sample
89 < snapshot_frame
90 .stake_offset
91 .checked_add(snapshot_frame.stake_amount)
92 .unwrap()),
93 }
94}