forest/utils/proofs_api/
parameters.rs1use std::{
9 fs::File as SyncFile,
10 io,
11 path::{Path, PathBuf},
12};
13
14use ahash::HashMap;
15use anyhow::{Context, bail};
16use blake2b_simd::{Hash, State as Blake2b};
17use cid::Cid;
18use serde::{Deserialize, Serialize};
19use tracing::{debug, warn};
20
21const PROOF_DIGEST_LEN: usize = 16;
22
23const FOREST_FORCE_TRUST_PARAMS_ENV: &str = "FOREST_FORCE_TRUST_PARAMS";
25
26pub(super) const PROOFS_PARAMETER_CACHE_ENV: &str = "FIL_PROOFS_PARAMETER_CACHE";
29
30const PARAM_DIR: &str = "filecoin-proof-parameters";
32
33pub(super) const DEFAULT_PARAMETERS: &str = include_str!("./parameters.json");
36
37pub(super) type ParameterMap = HashMap<String, ParameterData>;
39
40#[derive(Debug, Deserialize, Serialize, Clone)]
42pub(super) struct ParameterData {
43 #[serde(with = "crate::lotus_json::stringify")]
44 pub cid: Cid,
45 #[serde(with = "hex::serde")]
46 pub digest: [u8; PROOF_DIGEST_LEN],
47 pub sector_size: u64,
48}
49
50pub(super) async fn check_parameter_file(path: &Path, info: &ParameterData) -> anyhow::Result<()> {
53 crate::def_is_env_truthy!(force_trust_params, FOREST_FORCE_TRUST_PARAMS_ENV);
54
55 if force_trust_params() {
56 warn!("Assuming parameter files are okay. Do not use in production!");
57 return Ok(());
58 }
59
60 let hash = tokio::task::spawn_blocking({
61 let mut reader = std::io::BufReader::new(SyncFile::open(path)?);
62 let mut hasher = Blake2b::new();
63 move || -> io::Result<Hash> {
64 std::io::copy(&mut reader, &mut hasher)?;
65 Ok(hasher.finalize())
66 }
67 })
68 .await??;
69
70 let hash_chunk = hash
71 .as_bytes()
72 .get(..PROOF_DIGEST_LEN)
73 .context("invalid digest length")?;
74 if info.digest == hash_chunk {
75 debug!("Parameter file {:?} is ok", path);
76 Ok(())
77 } else {
78 bail!(
79 "Checksum mismatch in param file {:?}. ({:x?} != {:x?})",
80 path,
81 hash_chunk,
82 info.digest,
83 )
84 }
85}
86
87pub(super) fn param_dir(data_dir: &Path) -> PathBuf {
91 std::env::var(PROOFS_PARAMETER_CACHE_ENV)
92 .ok()
93 .and_then(|v| {
94 if v.is_empty() {
95 None
96 } else {
97 Some(PathBuf::from(v))
98 }
99 })
100 .unwrap_or_else(|| data_dir.join(PARAM_DIR))
101}
102
103fn set_proofs_parameter_cache_dir_env(data_dir: &Path) {
115 unsafe { std::env::set_var(PROOFS_PARAMETER_CACHE_ENV, param_dir(data_dir)) };
116}
117
118pub fn maybe_set_proofs_parameter_cache_dir_env(data_dir: &Path) {
121 if std::env::var(PROOFS_PARAMETER_CACHE_ENV).is_err() {
122 set_proofs_parameter_cache_dir_env(data_dir);
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[tokio::test]
131 async fn test_proof_file_check() {
132 let tempfile = tempfile::Builder::new().tempfile().unwrap();
133 let path = tempfile.path();
134
135 let data = b"Cthulhu fhtagn!";
136 std::fs::write(path, data).unwrap();
137
138 let mut hasher = Blake2b::new();
139 hasher.update(data);
140 let digest = hasher
141 .finalize()
142 .as_bytes()
143 .get(..PROOF_DIGEST_LEN)
144 .unwrap()
145 .to_owned();
146
147 let param_data = ParameterData {
148 cid: Cid::default(),
149 digest: digest.try_into().unwrap(),
150 sector_size: 32,
151 };
152
153 check_parameter_file(path, ¶m_data).await.unwrap()
154 }
155
156 #[tokio::test]
157 async fn test_proof_file_check_no_file() {
158 let param_data = ParameterData {
159 cid: Cid::default(),
160 digest: [0; PROOF_DIGEST_LEN],
161 sector_size: 32,
162 };
163
164 let path = Path::new("cthulhuazathoh.dagon");
165 let ret = check_parameter_file(path, ¶m_data).await;
166 assert_eq!(
167 ret.unwrap_err().downcast_ref::<io::Error>().unwrap().kind(),
168 io::ErrorKind::NotFound
169 );
170 }
171}