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(PathBuf::from(PROOFS_PARAMETER_CACHE_ENV))
93 .map(PathBuf::from)
94 .unwrap_or_else(|_| data_dir.join(PARAM_DIR))
95}
96
97fn set_proofs_parameter_cache_dir_env(data_dir: &Path) {
109 unsafe { std::env::set_var(PROOFS_PARAMETER_CACHE_ENV, param_dir(data_dir)) };
110}
111
112pub fn maybe_set_proofs_parameter_cache_dir_env(data_dir: &Path) {
115 if std::env::var(PROOFS_PARAMETER_CACHE_ENV).is_err() {
116 set_proofs_parameter_cache_dir_env(data_dir);
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[tokio::test]
125 async fn test_proof_file_check() {
126 let tempfile = tempfile::Builder::new().tempfile().unwrap();
127 let path = tempfile.path();
128
129 let data = b"Cthulhu fhtagn!";
130 std::fs::write(path, data).unwrap();
131
132 let mut hasher = Blake2b::new();
133 hasher.update(data);
134 let digest = hasher
135 .finalize()
136 .as_bytes()
137 .get(..PROOF_DIGEST_LEN)
138 .unwrap()
139 .to_owned();
140
141 let param_data = ParameterData {
142 cid: Cid::default(),
143 digest: digest.try_into().unwrap(),
144 sector_size: 32,
145 };
146
147 check_parameter_file(path, ¶m_data).await.unwrap()
148 }
149
150 #[tokio::test]
151 async fn test_proof_file_check_no_file() {
152 let param_data = ParameterData {
153 cid: Cid::default(),
154 digest: [0; PROOF_DIGEST_LEN],
155 sector_size: 32,
156 };
157
158 let path = Path::new("cthulhuazathoh.dagon");
159 let ret = check_parameter_file(path, ¶m_data).await;
160 assert_eq!(
161 ret.unwrap_err().downcast_ref::<io::Error>().unwrap().kind(),
162 io::ErrorKind::NotFound
163 );
164 }
165}