clockwork_network/instructions/
entry_create.rs

1use {
2    crate::{errors::ClockworkError, state::*},
3    anchor_lang::{prelude::*, solana_program::{instruction::Instruction, system_program}},
4    anchor_spl::{associated_token::get_associated_token_address, token::TokenAccount},
5    clockwork_crank::state::{CrankResponse, Queue, SEED_QUEUE},
6    std::mem::size_of,
7};
8
9#[derive(Accounts)]
10pub struct EntryCreate<'info> {
11    #[account(seeds = [SEED_AUTHORITY], bump)]
12    pub authority: Box<Account<'info, Authority>>,
13
14    #[account(seeds = [SEED_CONFIG], bump)]
15    pub config: Box<Account<'info, Config>>,
16
17    #[account(
18        init,
19        seeds = [
20            SEED_SNAPSHOT_ENTRY,
21            snapshot.key().as_ref(),
22            snapshot.node_count.to_be_bytes().as_ref()
23        ],
24        bump,
25        payer = payer,
26        space = 8 + size_of::<SnapshotEntry>(),
27    )]
28    pub entry: Account<'info, SnapshotEntry>,
29
30    #[account(
31        seeds = [
32            SEED_NODE,
33            node.id.to_be_bytes().as_ref(),
34        ],
35        bump,
36        constraint = node.id == snapshot.node_count @ ClockworkError::InvalidNode
37    )]
38    pub node: Box<Account<'info, Node>>,
39
40    #[account(mut)]
41    pub payer: Signer<'info>,
42
43    #[account(seeds = [SEED_REGISTRY], bump)]
44    pub registry: Box<Account<'info, Registry>>,
45
46    #[account(
47        mut,
48        seeds = [
49            SEED_SNAPSHOT,
50            snapshot.id.to_be_bytes().as_ref()
51        ],
52        bump,
53        constraint = snapshot.status == SnapshotStatus::InProgress @ ClockworkError::SnapshotNotInProgress,
54        constraint = snapshot.node_count < registry.node_count,
55    )]
56    pub snapshot: Account<'info, Snapshot>,
57
58    #[account(
59        signer, 
60        seeds = [
61            SEED_QUEUE, 
62            authority.key().as_ref(), 
63            "snapshot".as_bytes()
64        ], 
65        seeds::program = clockwork_crank::ID,
66        bump,
67        has_one = authority
68    )]
69    pub snapshot_queue: Account<'info, Queue>,
70
71    #[account(
72        associated_token::authority = node,
73        associated_token::mint = config.mint,
74    )]
75    pub stake: Account<'info, TokenAccount>,
76
77    #[account(address = system_program::ID)]
78    pub system_program: Program<'info, System>,
79}
80
81pub fn handler(ctx: Context<EntryCreate>) -> Result<CrankResponse> {
82    // Get accounts
83    let authority = &ctx.accounts.authority;
84    let config = &ctx.accounts.config;
85    let entry = &mut ctx.accounts.entry;
86    let node = &ctx.accounts.node;
87    let registry = &ctx.accounts.registry;
88    let stake = &ctx.accounts.stake;
89    let snapshot = &mut ctx.accounts.snapshot;
90    let snapshot_queue = &ctx.accounts.snapshot_queue;
91    let system_program = &ctx.accounts.system_program;
92
93    // Capture the snapshot entry
94    snapshot.capture(entry, node, stake)?;
95
96    // Build the next crank instruction
97    let next_instruction = if snapshot.node_count < registry.node_count {
98        // There are more nodes in the registry. Continue creating snapshot entries.
99        let next_id = node.id.checked_add(1).unwrap();
100        let next_node_pubkey = Node::pubkey(next_id); 
101        let next_entry_pubkey = SnapshotEntry::pubkey(snapshot.key(), next_id);
102        let stake_pubkey = get_associated_token_address(&next_node_pubkey, &config.mint);
103        Some(
104             Instruction {
105                program_id: crate::ID,
106                accounts: vec![
107                    AccountMeta::new_readonly(authority.key(), false),
108                    AccountMeta::new_readonly(config.key(), false),
109                    AccountMeta::new(next_entry_pubkey, false),
110                    AccountMeta::new_readonly(next_node_pubkey, false),
111                    AccountMeta::new(clockwork_crank::payer::ID, true),
112                    AccountMeta::new_readonly(registry.key(), false),
113                    AccountMeta::new(snapshot.key(), false),
114                    AccountMeta::new_readonly(snapshot_queue.key(), true),
115                    AccountMeta::new_readonly(stake_pubkey, false),
116                    AccountMeta::new_readonly(system_program.key(), false)
117                ],
118                data: clockwork_crank::anchor::sighash("entry_create").into(),
119            }
120            .into()
121        )
122    } else {
123        // We have created entries for all the nodes. Activate the new snapshot.
124        Some(
125            Instruction {
126                program_id: crate::ID,
127                accounts: vec![
128                    AccountMeta::new_readonly(authority.key(), false),
129                    AccountMeta::new_readonly(config.key(), false),
130                    AccountMeta::new(Snapshot::pubkey(snapshot.id.checked_sub(1).unwrap()), false), // The current active snapshot
131                    AccountMeta::new(snapshot.key(), false), // The next active snapshot
132                    AccountMeta::new(registry.key(), false),
133                    AccountMeta::new_readonly(snapshot_queue.key(), true),
134                ],
135                data: clockwork_crank::anchor::sighash("snapshot_rotate").into(),
136            }
137            .into()
138        )
139    };
140
141    Ok(CrankResponse { next_instruction })
142}