Skip to main content

antegen_fiber_program/instructions/
update.rs

1use crate::constants::*;
2use crate::errors::AntegenFiberError;
3use crate::state::*;
4use anchor_lang::prelude::*;
5use anchor_lang::solana_program::instruction::Instruction;
6
7use super::create::{initialize_fiber, write_legacy, write_versioned};
8
9/// Accounts required by the `update_fiber` instruction.
10/// Thread PDA must be signer. Fiber must be pre-funded if not yet initialized.
11#[derive(Accounts)]
12#[instruction(fiber_index: u8)]
13pub struct Update<'info> {
14    /// Thread PDA - must be signer
15    pub thread: Signer<'info>,
16
17    /// CHECK: Validated via seeds — may not be initialized yet
18    #[account(
19        mut,
20        seeds = [SEED_THREAD_FIBER, thread.key().as_ref(), &[fiber_index]],
21        bump,
22    )]
23    pub fiber: UncheckedAccount<'info>,
24
25    pub system_program: Program<'info, System>,
26}
27
28pub fn update(
29    ctx: Context<Update>,
30    fiber_index: u8,
31    instruction: Option<Instruction>,
32    priority_fee: Option<u64>,
33    lookup_tables: Option<Vec<Pubkey>>,
34) -> Result<()> {
35    if let Some(ref lt) = lookup_tables {
36        require!(
37            lt.len() <= MAX_LOOKUP_TABLES_PER_FIBER,
38            AntegenFiberError::LookupTablesExceedMax
39        );
40    }
41
42    let thread_key = ctx.accounts.thread.key();
43    let fiber_info = ctx.accounts.fiber.to_account_info();
44
45    if fiber_info.data_len().eq(&0) {
46        // Not initialized — do full init (same as fiber_create)
47        let instruction = instruction.ok_or(anchor_lang::error::ErrorCode::InstructionMissing)?;
48        let fee = priority_fee.unwrap_or(0);
49        initialize_fiber(
50            &ctx.accounts.fiber,
51            &ctx.accounts.system_program,
52            &thread_key,
53            fiber_index,
54            &instruction,
55            fee,
56            lookup_tables.unwrap_or_default(),
57        )?;
58        return Ok(());
59    }
60
61    let fiber_read = {
62        let data = fiber_info.try_borrow_data()?;
63        Fiber::try_deserialize(&mut &data[..])?
64    };
65
66    match fiber_read {
67        Fiber::Legacy(mut state) => {
68            // Legacy fibers cannot grow to hold lookup_tables.
69            if let Some(ref lt) = lookup_tables {
70                require!(
71                    lt.is_empty(),
72                    AntegenFiberError::LegacyFiberLookupTablesUnsupported
73                );
74            }
75            state.thread = thread_key;
76            apply_instruction_update(&mut state.compiled_instruction, instruction)?;
77            if let Some(fee) = priority_fee {
78                state.priority_fee = fee;
79            }
80            state.last_executed = 0;
81            state.exec_count = 0;
82            write_legacy(&fiber_info, &state)?;
83        }
84        Fiber::V1(mut state) => {
85            state.version = CURRENT_FIBER_VERSION;
86            state.thread = thread_key;
87            apply_instruction_update(&mut state.compiled_instruction, instruction)?;
88            if let Some(fee) = priority_fee {
89                state.priority_fee = fee;
90            }
91            if let Some(lt) = lookup_tables {
92                state.lookup_tables = lt;
93            }
94            state.last_executed = 0;
95            state.exec_count = 0;
96            write_versioned(&fiber_info, &state)?;
97        }
98    }
99
100    Ok(())
101}
102
103/// Update the compiled_instruction blob.
104///   - `Some(ix)` → compile and store.
105///   - `None`     → wipe (empty vec, signals idle fiber).
106fn apply_instruction_update(
107    compiled_instruction: &mut Vec<u8>,
108    instruction: Option<Instruction>,
109) -> Result<()> {
110    if let Some(ix) = instruction {
111        let compiled = compile_instruction(ix)?;
112        *compiled_instruction = borsh::to_vec(&compiled)?;
113    } else {
114        compiled_instruction.clear();
115    }
116    Ok(())
117}