sp1_prover/worker/node/
light.rs1use std::sync::Arc;
2
3use sp1_core_executor::{ExecutionReport, Program, SP1Context, SP1CoreOpts};
4use sp1_core_machine::io::SP1Stdin;
5use sp1_hypercube::{
6 prover::{CpuShardProver, ProverSemaphore},
7 SP1VerifyingKey,
8};
9use sp1_primitives::io::SP1PublicValues;
10use sp1_verifier::SP1Proof;
11
12use crate::{
13 verify::{SP1Verifier, VerifierRecursionVks},
14 worker::{node::SP1NodeCore, AirProverWorker},
15 CpuSP1ProverComponents, SP1ProverComponents,
16};
17
18struct SP1LightNodeInner {
19 core: SP1NodeCore,
21 core_air_prover: Arc<<CpuSP1ProverComponents as SP1ProverComponents>::CoreProver>,
23 permits: ProverSemaphore,
25}
26
27pub struct SP1LightNode {
28 inner: Arc<SP1LightNodeInner>,
29}
30
31impl Clone for SP1LightNode {
32 fn clone(&self) -> Self {
33 Self { inner: self.inner.clone() }
34 }
35}
36
37impl SP1LightNode {
38 pub async fn new() -> Self {
39 Self::with_opts(SP1CoreOpts::default()).await
40 }
41
42 pub async fn with_opts(opts: SP1CoreOpts) -> Self {
44 tokio::task::spawn_blocking(|| {
46 let core_verifier = CpuSP1ProverComponents::core_verifier();
48 let core_air_prover =
49 Arc::new(CpuShardProver::new(core_verifier.shard_verifier().clone()));
50 let permits = ProverSemaphore::new(1);
51
52 let verifier = SP1Verifier::new(VerifierRecursionVks::default());
54 let core = SP1NodeCore::new(verifier, opts);
56
57 Self { inner: Arc::new(SP1LightNodeInner { core, core_air_prover, permits }) }
58 })
59 .await
60 .expect("failed to initialize light node")
61 }
62
63 pub async fn setup(&self, elf: &[u8]) -> anyhow::Result<SP1VerifyingKey> {
64 let program = Program::from(elf)
65 .map_err(|e| anyhow::anyhow!("failed to disassemble program: {}", e))?;
66 let program = Arc::new(program);
67 let (_, vk) = self.inner.core_air_prover.setup(program, self.inner.permits.clone()).await;
68 let vk = SP1VerifyingKey { vk };
69 Ok(vk)
70 }
71
72 pub async fn execute(
74 &self,
75 elf: &[u8],
76 stdin: SP1Stdin,
77 context: SP1Context<'static>,
78 ) -> anyhow::Result<(SP1PublicValues, [u8; 32], ExecutionReport)> {
79 self.inner.core.execute(elf, stdin, context).await
80 }
81
82 pub fn verify(&self, vk: &SP1VerifyingKey, proof: &SP1Proof) -> anyhow::Result<()> {
84 self.inner.core.verify(vk, proof)
85 }
86
87 #[inline]
88 pub fn inner(&self) -> &SP1NodeCore {
89 &self.inner.core
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use sp1_core_machine::utils::setup_logger;
96 use sp1_hypercube::HashableKey;
97 use tracing::Instrument;
98
99 use crate::worker::{cpu_worker_builder, SP1LocalNodeBuilder};
100
101 use super::*;
102
103 #[tokio::test]
104 async fn test_light_node() {
105 setup_logger();
106
107 let light_node =
108 SP1LightNode::new().instrument(tracing::info_span!("initialize light node")).await;
109
110 let node = SP1LocalNodeBuilder::from_worker_client_builder(cpu_worker_builder())
111 .build()
112 .instrument(tracing::info_span!("initialize full node"))
113 .await
114 .unwrap();
115
116 let elf = test_artifacts::FIBONACCI_ELF;
117 let stdin = SP1Stdin::default();
118
119 let context = SP1Context::default();
121 let (_, _, report) =
122 light_node.execute(&elf, stdin.clone(), context.clone()).await.unwrap();
123 tracing::info!("report: {:?}", report);
124 let light_node_vk = light_node.setup(&elf).await.unwrap();
126 let node_vk = node.setup(&elf).await.unwrap();
128 assert_eq!(light_node_vk.hash_koalabear(), node_vk.hash_koalabear());
130
131 let proof = node.prove(&elf, stdin, context).await.unwrap();
133 light_node.verify(&light_node_vk, &proof.proof).unwrap();
135
136 let node_vks = node.core().recursion_vks();
137 let light_node_vks = light_node.inner().recursion_vks();
138 assert_eq!(node_vks, light_node_vks, "If this assertion fails, run test `sp1_prover::worker::node::full::tests::make_verifier_vks`");
139 }
140}