clockwork_network/instructions/
snapshot_create.rs

1use anchor_spl::associated_token::get_associated_token_address;
2
3use {
4    crate::state::*,
5    anchor_lang::{prelude::*, solana_program::instruction::Instruction},
6    clockwork_crank::state::{CrankResponse, Queue, SEED_QUEUE},
7    std::mem::size_of,
8};
9
10#[derive(Accounts)]
11pub struct SnapshotCreate<'info> {
12    #[account(seeds = [SEED_AUTHORITY], bump)]
13    pub authority: Box<Account<'info, Authority>>,
14
15    #[account(seeds = [SEED_CONFIG], bump)]
16    pub config: Box<Account<'info, Config>>,
17
18    #[account(mut)]
19    pub payer: Signer<'info>,
20
21    #[account(mut, seeds = [SEED_REGISTRY], bump)]
22    pub registry: Account<'info, Registry>,
23
24    #[account(
25        init,
26        seeds = [
27            SEED_SNAPSHOT,
28            registry.snapshot_count.to_be_bytes().as_ref()
29        ],
30        bump,
31        space = 8 + size_of::<Snapshot>(),
32        payer = payer
33    )]
34    pub snapshot: Account<'info, Snapshot>,
35
36    #[account(
37        signer, 
38        seeds = [
39            SEED_QUEUE, 
40            authority.key().as_ref(), 
41            "snapshot".as_bytes()
42        ], 
43        seeds::program = clockwork_crank::ID,
44        bump,
45        has_one = authority
46    )]
47    pub snapshot_queue: Account<'info, Queue>,
48
49    #[account()]
50    pub system_program: Program<'info, System>,
51}
52
53pub fn handler(ctx: Context<SnapshotCreate>) -> Result<CrankResponse> {
54    // Get accounts
55    let authority = &ctx.accounts.authority;
56    let config = &ctx.accounts.config;
57    let registry = &mut ctx.accounts.registry;
58    let snapshot = &mut ctx.accounts.snapshot;
59    let snapshot_queue = &ctx.accounts.snapshot_queue;
60    let system_program = &ctx.accounts.system_program;
61
62    // Start a new snapshot
63    registry.new_snapshot(snapshot)?;
64
65    // Build the next crank instruction
66    let next_instruction = if registry.node_count > 0 {
67        // There are nodes in the registry. Begin creating snapshot entries.
68        let node_pubkey = Node::pubkey(0);
69        let entry_pubkey = SnapshotEntry::pubkey(snapshot.key(), 0);
70        let stake_pubkey = get_associated_token_address(&node_pubkey, &config.mint);
71        Some(
72             Instruction {
73                program_id: crate::ID,
74                accounts: vec![
75                    AccountMeta::new_readonly(authority.key(), false),
76                    AccountMeta::new_readonly(config.key(), false),
77                    AccountMeta::new(entry_pubkey, false),
78                    AccountMeta::new_readonly(node_pubkey, false),
79                    AccountMeta::new(clockwork_crank::payer::ID, true),
80                    AccountMeta::new_readonly(registry.key(), false),
81                    AccountMeta::new(snapshot.key(), false),
82                    AccountMeta::new_readonly(snapshot_queue.key(), true),
83                    AccountMeta::new_readonly(stake_pubkey, false),
84                    AccountMeta::new_readonly(system_program.key(), false)
85                ],
86                data: clockwork_crank::anchor::sighash("entry_create").into(),
87            }
88            .into()
89        )
90    } else {
91        // There are no nodes in the registry. Activate the new snapshot.
92        Some(
93            Instruction {
94                program_id: crate::ID,
95                accounts: vec![
96                    AccountMeta::new_readonly(authority.key(), false),
97                    AccountMeta::new_readonly(config.key(), false),
98                    AccountMeta::new(Snapshot::pubkey(snapshot.id.checked_sub(1).unwrap()), false), // The current active snapshot
99                    AccountMeta::new(snapshot.key(), false), // The next active snapshot
100                    AccountMeta::new(registry.key(), false),
101                    AccountMeta::new_readonly(snapshot_queue.key(), true),
102                ],
103                data: clockwork_crank::anchor::sighash("snapshot_rotate").into(),
104            }
105            .into()
106        )
107    };
108
109    Ok(CrankResponse { next_instruction })
110}