openvm_sdk/
fs.rs

1use std::{
2    fs::{create_dir_all, read, write, File},
3    path::Path,
4};
5
6use eyre::{Report, Result};
7#[cfg(feature = "evm-prove")]
8use openvm_native_recursion::halo2::wrapper::EvmVerifierByteCode;
9use serde::{de::DeserializeOwned, Serialize};
10
11use crate::codec::{Decode, Encode};
12#[cfg(feature = "evm-prove")]
13use crate::{types::EvmHalo2Verifier, OPENVM_VERSION};
14
15pub const EVM_HALO2_VERIFIER_INTERFACE_NAME: &str = "IOpenVmHalo2Verifier.sol";
16pub const EVM_HALO2_VERIFIER_PARENT_NAME: &str = "Halo2Verifier.sol";
17pub const EVM_HALO2_VERIFIER_BASE_NAME: &str = "OpenVmHalo2Verifier.sol";
18pub const EVM_VERIFIER_ARTIFACT_FILENAME: &str = "verifier.bytecode.json";
19
20#[cfg(feature = "evm-prove")]
21pub fn read_evm_halo2_verifier_from_folder<P: AsRef<Path>>(folder: P) -> Result<EvmHalo2Verifier> {
22    use std::fs::read_to_string;
23
24    let folder = folder
25        .as_ref()
26        .join("src")
27        .join(format!("v{}", OPENVM_VERSION));
28    let halo2_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_PARENT_NAME);
29    let openvm_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_BASE_NAME);
30    let interface_path = folder
31        .join("interfaces")
32        .join(EVM_HALO2_VERIFIER_INTERFACE_NAME);
33    let halo2_verifier_code = read_to_string(halo2_verifier_code_path)?;
34    let openvm_verifier_code = read_to_string(openvm_verifier_code_path)?;
35    let interface = read_to_string(interface_path)?;
36
37    let artifact_path = folder.join(EVM_VERIFIER_ARTIFACT_FILENAME);
38    let artifact: EvmVerifierByteCode = serde_json::from_reader(File::open(artifact_path)?)?;
39
40    Ok(EvmHalo2Verifier {
41        halo2_verifier_code,
42        openvm_verifier_code,
43        openvm_verifier_interface: interface,
44        artifact,
45    })
46}
47
48/// Writes three Solidity contracts into the following folder structure:
49///
50/// ```text
51/// halo2/
52/// └── src/
53///     └── v[OPENVM_VERSION]/
54///         ├── interfaces/
55///         │   └── IOpenVmHalo2Verifier.sol
56///         ├── OpenVmHalo2Verifier.sol
57///         └── Halo2Verifier.sol
58/// ```
59///
60/// If the relevant directories do not exist, they will be created.
61#[cfg(feature = "evm-prove")]
62pub fn write_evm_halo2_verifier_to_folder<P: AsRef<Path>>(
63    verifier: EvmHalo2Verifier,
64    folder: P,
65) -> Result<()> {
66    let folder = folder
67        .as_ref()
68        .join("src")
69        .join(format!("v{}", OPENVM_VERSION));
70    if !folder.exists() {
71        create_dir_all(&folder)?; // Make sure directories exist
72    }
73
74    let halo2_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_PARENT_NAME);
75    let openvm_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_BASE_NAME);
76    let interface_path = folder
77        .join("interfaces")
78        .join(EVM_HALO2_VERIFIER_INTERFACE_NAME);
79
80    if let Some(parent) = interface_path.parent() {
81        create_dir_all(parent)?;
82    }
83
84    write(halo2_verifier_code_path, verifier.halo2_verifier_code)
85        .expect("Failed to write halo2 verifier code");
86    write(openvm_verifier_code_path, verifier.openvm_verifier_code)
87        .expect("Failed to write openvm halo2 verifier code");
88    write(interface_path, verifier.openvm_verifier_interface)
89        .expect("Failed to write openvm halo2 verifier interface");
90
91    let artifact_path = folder.join(EVM_VERIFIER_ARTIFACT_FILENAME);
92    serde_json::to_writer(File::create(artifact_path)?, &verifier.artifact)?;
93
94    Ok(())
95}
96
97pub fn read_object_from_file<T: DeserializeOwned, P: AsRef<Path>>(path: P) -> Result<T> {
98    read_from_file_bitcode(path)
99}
100
101pub fn write_object_to_file<T: Serialize, P: AsRef<Path>>(path: P, data: T) -> Result<()> {
102    write_to_file_bitcode(path, data)
103}
104
105fn read_from_file_bitcode<T: DeserializeOwned, P: AsRef<Path>>(path: P) -> Result<T> {
106    let ret = read(&path)
107        .map_err(|e| read_error(&path, e.into()))
108        .and_then(|data| {
109            bitcode::deserialize(&data).map_err(|e: bitcode::Error| read_error(&path, e.into()))
110        })?;
111    Ok(ret)
112}
113
114fn write_to_file_bitcode<T: Serialize, P: AsRef<Path>>(path: P, data: T) -> Result<()> {
115    if let Some(parent) = path.as_ref().parent() {
116        create_dir_all(parent).map_err(|e| write_error(&path, e.into()))?;
117    }
118    bitcode::serialize(&data)
119        .map_err(|e| write_error(&path, e.into()))
120        .and_then(|bytes| write(&path, bytes).map_err(|e| write_error(&path, e.into())))?;
121    Ok(())
122}
123
124pub fn read_from_file_json<T: DeserializeOwned, P: AsRef<Path>>(path: P) -> Result<T> {
125    let ret: T = File::open(&path)
126        .and_then(|file| serde_json::from_reader(file).map_err(|e| e.into()))
127        .map_err(|e| read_error(&path, e.into()))?;
128    Ok(ret)
129}
130
131pub fn write_to_file_json<T: Serialize, P: AsRef<Path>>(path: P, data: T) -> Result<()> {
132    if let Some(parent) = path.as_ref().parent() {
133        create_dir_all(parent).map_err(|e| write_error(&path, e.into()))?;
134    }
135    File::create(&path)
136        .and_then(|file| serde_json::to_writer_pretty(file, &data).map_err(|e| e.into()))
137        .map_err(|e| write_error(&path, e.into()))?;
138    Ok(())
139}
140
141pub fn read_from_file_bytes<T: From<Vec<u8>>, P: AsRef<Path>>(path: P) -> Result<T> {
142    let bytes = read(path)?;
143    Ok(T::from(bytes))
144}
145
146pub fn write_to_file_bytes<T: Into<Vec<u8>>, P: AsRef<Path>>(path: P, data: T) -> Result<()> {
147    if let Some(parent) = path.as_ref().parent() {
148        create_dir_all(parent)?;
149    }
150    write(path, data.into())?;
151    Ok(())
152}
153
154pub fn decode_from_file<T: Decode, P: AsRef<Path>>(path: P) -> Result<T> {
155    let reader = &mut File::open(path)?;
156    let ret = T::decode(reader)?;
157    Ok(ret)
158}
159
160pub fn encode_to_file<T: Encode, P: AsRef<Path>>(path: P, data: T) -> Result<()> {
161    if let Some(parent) = path.as_ref().parent() {
162        create_dir_all(parent)?;
163    }
164    let writer = &mut File::create(path)?;
165    data.encode(writer)?;
166    Ok(())
167}
168
169fn read_error<P: AsRef<Path>>(path: P, error: Report) -> Report {
170    eyre::eyre!(
171        "reading from {} failed with the following error:\n    {}",
172        path.as_ref().display(),
173        error,
174    )
175}
176
177fn write_error<P: AsRef<Path>>(path: P, error: Report) -> Report {
178    eyre::eyre!(
179        "writing to {} failed with the following error:\n    {}",
180        path.as_ref().display(),
181        error,
182    )
183}