1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use clockwork_pool::cpi::accounts::Rotate;
use crate::errors::ClockworkError;
use {crate::state::*, anchor_lang::prelude::*};
#[derive(Accounts)]
pub struct RotatorTurn<'info> {
#[account(seeds = [SEED_CONFIG], bump)]
pub config: Account<'info, Config>,
#[account(
seeds = [
SEED_SNAPSHOT_ENTRY,
entry.snapshot.as_ref(),
entry.id.to_be_bytes().as_ref(),
],
bump,
has_one = snapshot,
has_one = worker,
constraint = is_valid_entry(&entry, &rotator, &snapshot).unwrap() @ ClockworkError::InvalidSnapshotEntry,
)]
pub entry: Account<'info, SnapshotEntry>,
#[account(mut, address = clockwork_pool::state::Pool::pubkey())]
pub pool: Account<'info, clockwork_pool::state::Pool>,
#[account(address = clockwork_pool::state::Config::pubkey())]
pub pool_config: Account<'info, clockwork_pool::state::Config>,
#[account(address = clockwork_pool::ID)]
pub pool_program: Program<'info, clockwork_pool::program::ClockworkPool>,
#[account(
mut,
seeds = [SEED_ROTATOR],
bump,
constraint = Clock::get().unwrap().slot >= rotator.last_slot.checked_add(config.slots_per_rotation).unwrap()
)]
pub rotator: Account<'info, Rotator>,
#[account()]
pub signer: Signer<'info>,
#[account(
seeds = [
SEED_SNAPSHOT,
snapshot.id.to_be_bytes().as_ref()
],
bump,
constraint = snapshot.status == SnapshotStatus::Current @ ClockworkError::SnapshotNotCurrent
)]
pub snapshot: Account<'info, Snapshot>,
#[account()]
pub worker: SystemAccount<'info>,
}
pub fn handler(ctx: Context<RotatorTurn>) -> Result<()> {
let pool = &mut ctx.accounts.pool;
let pool_config = &ctx.accounts.pool_config;
let pool_program = &ctx.accounts.pool_program;
let rotator = &mut ctx.accounts.rotator;
let worker = &ctx.accounts.worker;
let rotator_bump = *ctx.bumps.get("rotator").unwrap();
clockwork_pool::cpi::rotate(
CpiContext::new_with_signer(
pool_program.to_account_info(),
Rotate {
config: pool_config.to_account_info(),
rotator: rotator.to_account_info(),
pool: pool.to_account_info(),
worker: worker.to_account_info(),
},
&[&[SEED_ROTATOR, &[rotator_bump]]],
),
)?;
rotator.hash_nonce()?;
Ok(())
}
fn is_valid_entry(
entry: &Account<SnapshotEntry>,
rotator: &Account<Rotator>,
snapshot: &Account<Snapshot>,
) -> Result<bool> {
match rotator.nonce.checked_rem(snapshot.stake_total) {
None => Ok(false),
Some(sample) => Ok(sample >= entry.stake_offset
&& sample < entry.stake_offset.checked_add(entry.stake_amount).unwrap()),
}
}