Skip to main content

forest/utils/proofs_api/
parameters.rs

1// Copyright 2019-2026 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3//! This module contains the logic for storing and verifying the proofs parameters.
4//!
5//! The parameters are fetched from the network and stored in the cache directory. The cache directory can be set
6//! using the [`PROOFS_PARAMETER_CACHE_ENV`] environment variable. If not set, the default directory is used.
7
8use 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
23/// Environment variable that allows skipping checksum verification of the parameter files.
24const FOREST_FORCE_TRUST_PARAMS_ENV: &str = "FOREST_FORCE_TRUST_PARAMS";
25
26/// Environment variable to set the directory where proofs parameters are stored. Defaults to
27/// [`PARAM_DIR`] in the data directory.
28pub(super) const PROOFS_PARAMETER_CACHE_ENV: &str = "FIL_PROOFS_PARAMETER_CACHE";
29
30/// Default directory name for storing proofs parameters.
31const PARAM_DIR: &str = "filecoin-proof-parameters";
32
33/// Default parameters, as outlined in Lotus `v1.26.2`.
34/// <https://github.com/filecoin-project/filecoin-ffi/blob/b715c9403faf919e95fdc702cd651e842f18d890/parameters.json>
35pub(super) const DEFAULT_PARAMETERS: &str = include_str!("./parameters.json");
36
37/// Map of parameter data, to be deserialized from the parameter file.
38pub(super) type ParameterMap = HashMap<String, ParameterData>;
39
40/// Data structure for retrieving the proof parameter data from provided JSON.
41#[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
50/// Ensures the parameter file is downloaded and has the correct checksum.
51/// This behavior can be disabled by setting the [`FOREST_FORCE_TRUST_PARAMS_ENV`] environment variable to 1.
52pub(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
87// Proof parameter file directory. Defaults to
88// %DATA_DIR/filecoin-proof-parameters unless the FIL_PROOFS_PARAMETER_CACHE
89// environment variable is set.
90pub(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
103/// Forest uses a set of external crates for verifying the proofs generated by
104/// the miners. These external crates require a specific set of parameter files
105/// to be located at in a specific folder. By default, it is
106/// `/var/tmp/filecoin-proof-parameters` but it can be overridden by the
107/// `FIL_PROOFS_PARAMETER_CACHE` environment variable. Forest will automatically
108/// download the parameter files from Cloudflare/IPFS and verify their validity. For
109/// consistency, Forest will prefer to download the files it's local data
110/// directory. To this end, the `FIL_PROOFS_PARAMETER_CACHE` environment
111/// variable is updated before the parameters are downloaded.
112///
113/// More information available [here](https://github.com/filecoin-project/rust-fil-proofs/blob/8f5bd86be36a55e33b9b293ba22ea13ca1f28163/README.md?plain=1#L219-L235).
114fn 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
118/// Optionally set the proofs parameter cache directory environment variable if it is not already
119/// set. See [`set_proofs_parameter_cache_dir_env`] for more details.
120pub 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, &param_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, &param_data).await;
166        assert_eq!(
167            ret.unwrap_err().downcast_ref::<io::Error>().unwrap().kind(),
168            io::ErrorKind::NotFound
169        );
170    }
171}