forest/utils/proofs_api/
parameters.rs1use std::{
9 fs::File as SyncFile,
10 io::{self, BufReader as SyncBufReader, copy as sync_copy},
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
21use crate::utils::misc::env::is_env_truthy;
22
23const PROOF_DIGEST_LEN: usize = 16;
24
25const FOREST_FORCE_TRUST_PARAMS_ENV: &str = "FOREST_FORCE_TRUST_PARAMS";
27
28pub(super) const PROOFS_PARAMETER_CACHE_ENV: &str = "FIL_PROOFS_PARAMETER_CACHE";
31
32const PARAM_DIR: &str = "filecoin-proof-parameters";
34
35pub(super) const DEFAULT_PARAMETERS: &str = include_str!("./parameters.json");
38
39pub(super) type ParameterMap = HashMap<String, ParameterData>;
41
42#[derive(Debug, Deserialize, Serialize, Clone)]
44pub(super) struct ParameterData {
45 #[serde(with = "crate::lotus_json::stringify")]
46 pub cid: Cid,
47 #[serde(with = "hex::serde")]
48 pub digest: [u8; PROOF_DIGEST_LEN],
49 pub sector_size: u64,
50}
51
52pub(super) async fn check_parameter_file(path: &Path, info: &ParameterData) -> anyhow::Result<()> {
55 if is_env_truthy(FOREST_FORCE_TRUST_PARAMS_ENV) {
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 file = SyncFile::open(path)?;
62 move || -> Result<Hash, io::Error> {
63 let mut reader = SyncBufReader::new(file);
64 let mut hasher = Blake2b::new();
65 sync_copy(&mut reader, &mut hasher)?;
66 Ok(hasher.finalize())
67 }
68 })
69 .await??;
70
71 let hash_chunk = hash
72 .as_bytes()
73 .get(..PROOF_DIGEST_LEN)
74 .context("invalid digest length")?;
75 if info.digest == hash_chunk {
76 debug!("Parameter file {:?} is ok", path);
77 Ok(())
78 } else {
79 bail!(
80 "Checksum mismatch in param file {:?}. ({:x?} != {:x?})",
81 path,
82 hash_chunk,
83 info.digest,
84 )
85 }
86}
87
88pub(super) fn param_dir(data_dir: &Path) -> PathBuf {
92 std::env::var(PROOFS_PARAMETER_CACHE_ENV)
93 .ok()
94 .and_then(|v| {
95 if v.is_empty() {
96 None
97 } else {
98 Some(PathBuf::from(v))
99 }
100 })
101 .unwrap_or_else(|| data_dir.join(PARAM_DIR))
102}
103
104fn set_proofs_parameter_cache_dir_env(data_dir: &Path) {
116 unsafe { std::env::set_var(PROOFS_PARAMETER_CACHE_ENV, param_dir(data_dir)) };
117}
118
119pub fn maybe_set_proofs_parameter_cache_dir_env(data_dir: &Path) {
122 if std::env::var(PROOFS_PARAMETER_CACHE_ENV).is_err() {
123 set_proofs_parameter_cache_dir_env(data_dir);
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[tokio::test]
132 async fn test_proof_file_check() {
133 let tempfile = tempfile::Builder::new().tempfile().unwrap();
134 let path = tempfile.path();
135
136 let data = b"Cthulhu fhtagn!";
137 std::fs::write(path, data).unwrap();
138
139 let mut hasher = Blake2b::new();
140 hasher.update(data);
141 let digest = hasher
142 .finalize()
143 .as_bytes()
144 .get(..PROOF_DIGEST_LEN)
145 .unwrap()
146 .to_owned();
147
148 let param_data = ParameterData {
149 cid: Cid::default(),
150 digest: digest.try_into().unwrap(),
151 sector_size: 32,
152 };
153
154 check_parameter_file(path, ¶m_data).await.unwrap()
155 }
156
157 #[tokio::test]
158 async fn test_proof_file_check_no_file() {
159 let param_data = ParameterData {
160 cid: Cid::default(),
161 digest: [0; PROOF_DIGEST_LEN],
162 sector_size: 32,
163 };
164
165 let path = Path::new("cthulhuazathoh.dagon");
166 let ret = check_parameter_file(path, ¶m_data).await;
167 assert_eq!(
168 ret.unwrap_err().downcast_ref::<io::Error>().unwrap().kind(),
169 io::ErrorKind::NotFound
170 );
171 }
172}