data_anchor_blober/instructions/
create_checkpoint.rs1use anchor_lang::{prelude::*, solana_program::clock::Slot};
2
3use crate::{
4 checkpoint::CheckpointConfig, error::ErrorCode, state::checkpoint::Checkpoint,
5 CHECKPOINT_CONFIG_SEED, CHECKPOINT_PDA_SIGNER_SEED, CHECKPOINT_SEED, GROTH16_PROOF_SIZE, SEED,
6};
7
8#[derive(Accounts)]
9#[instruction(blober: Pubkey)]
10pub struct CreateCheckpoint<'info> {
11 #[account(
12 init_if_needed,
13 payer = payer,
14 space = Checkpoint::DISCRIMINATOR.len() + Checkpoint::INIT_SPACE,
15 seeds = [
16 SEED,
17 CHECKPOINT_SEED,
18 blober.as_ref(),
19 ],
20 bump
21 )]
22 pub checkpoint: Account<'info, Checkpoint>,
23
24 #[account(
25 seeds = [
26 SEED,
27 CHECKPOINT_SEED,
28 CHECKPOINT_CONFIG_SEED,
29 blober.as_ref(),
30 ],
31 bump,
32 )]
33 pub checkpoint_config: Account<'info, CheckpointConfig>,
34
35 #[account(
36 mut,
37 seeds = [
38 SEED,
39 CHECKPOINT_SEED,
40 CHECKPOINT_PDA_SIGNER_SEED,
41 blober.as_ref(),
42 ],
43 seeds::program = checkpoint_config.authority,
44 bump,
45 )]
46 pub pda_signer: Signer<'info>,
47
48 #[account(mut)]
49 pub payer: Signer<'info>,
50
51 pub system_program: Program<'info, System>,
52}
53
54pub fn create_checkpoint_handler(
55 ctx: Context<CreateCheckpoint>,
56 blober: Pubkey,
57 proof: [u8; GROTH16_PROOF_SIZE],
58 public_values: Vec<u8>,
59 verification_key: String,
60 slot: Slot,
61) -> Result<()> {
62 let new_checkpoint = Checkpoint::new(proof, public_values, verification_key, slot)?;
63
64 let public_value_blober = new_checkpoint.blober()?;
65
66 if public_value_blober != blober {
67 return Err(error!(ErrorCode::BloberMismatch));
68 }
69
70 if ctx.accounts.checkpoint.slot == 0 {
71 return ctx.accounts.checkpoint.store(new_checkpoint);
72 }
73
74 if public_value_blober != ctx.accounts.checkpoint.blober()? {
75 return Err(error!(ErrorCode::BloberMismatch));
76 }
77
78 if ctx.accounts.checkpoint.slot >= slot {
79 return Err(error!(ErrorCode::SlotTooLow));
80 }
81
82 if new_checkpoint.initial_hash()? != ctx.accounts.checkpoint.final_hash()? {
83 return Err(error!(ErrorCode::ProofHashMismatch));
84 }
85
86 ctx.accounts.checkpoint.store(new_checkpoint)
87}
88
89#[cfg(all(test, feature = "sp1"))]
90mod tests {
91 use anchor_lang::{
92 prelude::{AccountMeta, Pubkey},
93 ToAccountMetas,
94 };
95
96 use crate::accounts::CreateCheckpoint;
97
98 #[test]
99 fn test_first_account_is_the_checkpoint() {
100 let checkpoint = Pubkey::new_unique();
101 let checkpoint_config = Pubkey::new_unique();
102 let pda_signer = Pubkey::new_unique();
103 let payer = Pubkey::new_unique();
104 let system_program = Pubkey::new_unique();
105
106 let account = CreateCheckpoint {
107 checkpoint,
108 checkpoint_config,
109 payer,
110 pda_signer,
111 system_program,
112 };
113
114 let expected = AccountMeta {
115 pubkey: checkpoint,
116 is_signer: false,
117 is_writable: true,
118 };
119
120 let is_signer = None;
121 let actual = &account.to_account_metas(is_signer)[0];
122 assert_eq!(actual, &expected);
123 }
124}