1use std::{path::PathBuf, sync::{Arc}, collections::{HashMap}, time::Duration};
2
3use color_eyre::eyre;
4use debug_env::{BokkenValidatorMessage, BokkenAccountData};
5use executor::BokkenSolanaContext;
6use ipc_comm::IPCComm;
7use sol_syscalls::{BokkenSyscalls, BokkenSyscallMsg};
8use solana_program::{pubkey::Pubkey, program_stubs::set_syscall_stubs};
9use bpaf::Bpaf;
10use tokio::{net::UnixStream, sync::{Mutex, mpsc}, time::sleep};
11
12
13pub mod sol_syscalls;
14pub mod executor;
15pub mod debug_env;
16pub mod ipc_comm;
17
18
19#[derive(Clone, Debug, Bpaf)]
20#[bpaf(options, version)]
21struct CommandOptions {
23 #[bpaf(short, long, argument::<PathBuf>("PATH"))]
25 socket_path: PathBuf,
26
27 #[bpaf(short, long, argument::<Pubkey>("PUBKEY"))]
29 program_id: Pubkey,
30}
31
32async fn ipc_read_loop(
33 comm: Arc<Mutex<IPCComm>>,
34 syscall_sender: mpsc::Sender<BokkenSyscallMsg>,
35 invoke_result_senders: Arc<Mutex<HashMap<u64, mpsc::Sender<(u64, HashMap<Pubkey, BokkenAccountData>)>>>>
36) -> eyre::Result<()> {
37 loop {
38 let msg = {
40 let mut comm = comm.lock().await;
41 if comm.stopped() {
42 break;
43 }
44 if let Some(msg) = comm.recv_msg().await? {
45 msg
46 }else{
47 sleep(Duration::from_millis(1)).await;
48 continue;
49 }
50 };
51 match msg {
52 BokkenValidatorMessage::Invoke {
53 nonce,
54 program_id,
55 instruction,
56 account_metas,
57 account_datas,
58 call_depth
59 } => {
60 let context = BokkenSolanaContext::new(
61 program_id,
62 instruction,
63 account_metas.into_iter().map(|v|{v.into()}).collect(),
64 account_datas,
65 nonce,
66 call_depth
67 );
68 syscall_sender.send(
69 BokkenSyscallMsg::PushContext{
70 ctx: context,
71 msg_sender_clone: syscall_sender.clone()
72 }
73 ).await?;
74 },
75 BokkenValidatorMessage::CrossProgramInvokeResult {
76 nonce,
77 return_code,
78 account_datas
79 } => {
80 if let Some(sender) = invoke_result_senders.lock().await.remove(&nonce) {
81 sender.send((return_code, account_datas)).await?;
82 }
83 },
84 }
85 }
86 Ok(())
87}
88
89pub async fn bokken_runtime_main() -> eyre::Result<()> {
90 let opts = command_options().run();
91 let comm = Arc::new(Mutex::new(IPCComm::new(UnixStream::connect(opts.socket_path).await?)));
94 {
95 comm.lock().await.send_msg(opts.program_id).await?;
97 }
98 let (syscall_sender, syscall_receiver) = mpsc::channel::<BokkenSyscallMsg>(1);
99 let invoke_result_senders = Arc::new(Mutex::new(HashMap::new()));
100 let syscall_mgr = Box::new(BokkenSyscalls::new(
101 comm.clone(),
102 opts.program_id,
103 invoke_result_senders.clone(),
104 syscall_receiver
105 ));
106 set_syscall_stubs(syscall_mgr);
108 println!("bokken_runtime_main: Sent program ID, set syscalls, awaiting execution requests...");
109 ipc_read_loop(comm, syscall_sender, invoke_result_senders).await?;
111 Ok(())
112}
113
114#[macro_export]
115macro_rules! bokken_program {
116 ($program_crate_name:ident) => {
117 extern crate $program_crate_name;
118
119 #[tokio::main]
120 async fn main() -> color_eyre::eyre::Result<()> {
121 color_eyre::install()?;
122 bokken_runtime::bokken_runtime_main().await
123 }
124 };
125}