clockwork_network/instructions/
entry_close.rs

1use {
2    crate::state::*,
3    anchor_lang::{prelude::*, solana_program::instruction::Instruction},
4    clockwork_crank::state::{CrankResponse, Queue},
5};
6
7#[derive(Accounts)]
8pub struct EntryClose<'info> {
9    #[account(seeds = [SEED_AUTHORITY], bump)]
10    pub authority: Account<'info, Authority>,
11
12    #[account(
13        mut,
14        seeds = [
15            SEED_SNAPSHOT_ENTRY,
16            entry.snapshot.as_ref(),
17            entry.id.to_be_bytes().as_ref()
18        ],
19        bump,
20        has_one = snapshot,
21    )]
22    pub entry: Account<'info, SnapshotEntry>,
23
24    #[account(
25        mut,
26        seeds = [
27            SEED_SNAPSHOT,
28            snapshot.id.to_be_bytes().as_ref()
29        ],
30        bump,
31        constraint = snapshot.status == SnapshotStatus::Closing,
32    )]
33    pub snapshot: Account<'info, Snapshot>,
34
35    #[account(mut, has_one = authority, constraint = snapshot_queue.id.eq("snapshot"))]
36    pub snapshot_queue: Account<'info, Queue>,
37}
38
39pub fn handler(ctx: Context<EntryClose>) -> Result<CrankResponse> {
40    // Get accounts
41    let authority = &ctx.accounts.authority;
42    let entry = &mut ctx.accounts.entry;
43    let snapshot = &mut ctx.accounts.snapshot;
44    let snapshot_queue = &mut ctx.accounts.snapshot_queue;
45
46    // If snapshot is not closing, then noop and try again on next invocation.
47    if snapshot.status != SnapshotStatus::Closing {
48        return Ok(CrankResponse::default());
49    }
50
51    // Close the entry account.
52    let entry_id = entry.id.clone();
53    let entry_lamports = entry.to_account_info().lamports();
54    **entry.to_account_info().lamports.borrow_mut() = 0;
55    **snapshot_queue.to_account_info().lamports.borrow_mut() = snapshot_queue
56        .to_account_info()
57        .lamports()
58        .checked_add(entry_lamports)
59        .unwrap();
60
61    // If this is the last entry of the snapshot, then also close the snapshot account.
62    let snapshot_pubkey = snapshot.key().clone();
63    let snapshot_node_count = snapshot.node_count.clone();
64    if entry_id == snapshot_node_count.checked_sub(1).unwrap() {
65        let snapshot_lamports = snapshot.to_account_info().lamports();
66        **snapshot.to_account_info().lamports.borrow_mut() = 0;
67        **snapshot_queue.to_account_info().lamports.borrow_mut() = snapshot_queue
68            .to_account_info()
69            .lamports()
70            .checked_add(snapshot_lamports)
71            .unwrap();
72    }
73
74    // Use dynamic accounts to run with the next snapshot on the next invocation
75    let next_instruction = if entry_id < snapshot.node_count.checked_sub(1).unwrap() {
76        let next_entry_pubkey =
77            SnapshotEntry::pubkey(snapshot_pubkey, entry.id.checked_add(1).unwrap());
78        Some(
79            Instruction {
80                program_id: crate::ID,
81                accounts: vec![
82                    AccountMeta::new_readonly(authority.key(), false),
83                    AccountMeta::new(next_entry_pubkey, false),
84                    AccountMeta::new(snapshot.key(), false),
85                    AccountMeta::new(snapshot_queue.key(), false),
86                ],
87                data: clockwork_crank::anchor::sighash("entry_close").into(),
88            }
89            .into(),
90        )
91    } else {
92        None
93    };
94
95    Ok(CrankResponse { next_instruction })
96}