Skip to content

Commit

Permalink
Add seal regression testing support (#1765)
Browse files Browse the repository at this point in the history
* feat: add seal regression testing support
* feat: add tests from v16 and v18
     - v17 missed result collection for various reasons, but could always be added later if needed

* fix: skip regression tests on macos (parameters missing)
  • Loading branch information
cryptonemo authored Oct 21, 2024
1 parent 266acc3 commit be65d20
Show file tree
Hide file tree
Showing 10 changed files with 939 additions and 36 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,22 @@ Some results are displayed at the command line, or alternatively written as JSON

Note: On macOS you need `gtime` (`brew install gnu-time`), as the built in `time` command is not enough.

## Regression Testing

Within the `filecoin-proofs` crate there is a regression suite. The idea is to record some generated proofs at various proof release versions, so that future versions/revisions can always ensure that it can properly verify historical proofs as expected.

By default, there is a test that verifies all known regression records that exist within the source tree.

In order to generate a new set of regression records, the feature flag `persist-regression-proofs` must be used.

When the feature is used and all of the `filecoin-proofs` tests are run (including the ignored tests), the following files are written to disk:

```
filecoin-proofs/tests/seal_regression_records.json
```

Once the new files are generated with a given proof version, they should be renamed appropriately and added to the repository and then referenced for verification during routine testing in the `filecoin-proofs/tests/regression.rs` source (see the `const` values at the top and go from there).

## Logging

For better logging with backtraces on errors, developers should use `expects` rather than `expect` on `Result<T, E>` and `Option<T>`.
Expand Down
2 changes: 2 additions & 0 deletions filecoin-proofs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ serde = { workspace = true, features = ["rc", "derive"] }
serde_json.workspace = true
sha2.workspace = true
typenum.workspace = true
file-lock = { version = "2.1.10", optional = true }

[dev-dependencies]
# Sorted alphabetically
Expand Down Expand Up @@ -86,6 +87,7 @@ fixed-rows-to-discard = [
"storage-proofs-post/fixed-rows-to-discard",
"storage-proofs-update/fixed-rows-to-discard",
]
persist-regression-proofs = ["dep:file-lock"]

[[bench]]
name = "preprocessing"
Expand Down
17 changes: 3 additions & 14 deletions filecoin-proofs/src/types/porep_config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::path::PathBuf;

use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use storage_proofs_core::{
api_version::{ApiFeature, ApiVersion},
merkle::MerkleTreeTrait,
Expand All @@ -18,7 +19,7 @@ use crate::{
POREP_PARTITIONS,
};

#[derive(Clone, Debug)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PoRepConfig {
pub sector_size: SectorSize,
pub partitions: PoRepProofPartitions,
Expand Down Expand Up @@ -79,19 +80,7 @@ impl PoRepConfig {
api_version: ApiVersion,
api_features: Vec<ApiFeature>,
) -> Result<Self> {
let mut config = Self {
sector_size: SectorSize(sector_size),
partitions: PoRepProofPartitions(
*POREP_PARTITIONS
.read()
.expect("POREP_PARTITIONS poisoned")
.get(&sector_size)
.expect("unknown sector size"),
),
porep_id,
api_version,
api_features: vec![],
};
let mut config = PoRepConfig::new_groth16(sector_size, porep_id, api_version);
for feature in api_features {
config.enable_feature(feature)?;
}
Expand Down
4 changes: 3 additions & 1 deletion filecoin-proofs/src/types/porep_proof_partitions.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#[derive(Clone, Copy, Debug)]
use serde::{Deserialize, Serialize};

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct PoRepProofPartitions(pub u8);

impl From<PoRepProofPartitions> for usize {
Expand Down
3 changes: 2 additions & 1 deletion filecoin-proofs/src/types/sector_size.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use fr32::to_unpadded_bytes;
use serde::{Deserialize, Serialize};

use crate::types::{PaddedBytesAmount, UnpaddedBytesAmount};

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct SectorSize(pub u64);

impl From<u64> for SectorSize {
Expand Down
101 changes: 83 additions & 18 deletions filecoin-proofs/tests/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,15 @@ use filecoin_proofs::constants::{

#[cfg(feature = "big-tests")]
use filecoin_proofs::{
SectorShape512MiB, SectorShape64GiB, SECTOR_SIZE_512_MIB, SECTOR_SIZE_64_GIB,
SectorShape512MiB, SectorShape64GiB, SectorShape8MiB, SECTOR_SIZE_512_MIB, SECTOR_SIZE_64_GIB,
SECTOR_SIZE_8_MIB,
};

#[cfg(feature = "persist-regression-proofs")]
mod regression;
#[cfg(feature = "persist-regression-proofs")]
use regression::persist_generated_proof_for_regression_testing;

// Use a fixed PoRep ID, so that the parents cache can be re-used between some tests.
// Note however, that parents caches cannot be shared when testing the differences
// between API v1 and v2 behaviour (since the parent caches will be different for the
Expand Down Expand Up @@ -403,30 +409,68 @@ fn test_seal_lifecycle_32kib_base_8() -> Result<()> {

#[cfg(feature = "big-tests")]
#[test]
fn test_seal_lifecycle_512mib_porep_id_v1_top_8_0_0_api_v1() -> Result<()> {
use filecoin_proofs::{SectorShape512MiB, SECTOR_SIZE_512_MIB};
let porep_id_v1: u64 = 2; // This is a RegisteredSealProof value
fn test_seal_lifecycle_8mib_base_8() -> Result<()> {
let test_inputs = vec![
(ARBITRARY_POREP_ID_V1_0_0, ApiVersion::V1_0_0, Vec::new()),
(ARBITRARY_POREP_ID_V1_1_0, ApiVersion::V1_1_0, Vec::new()),
(ARBITRARY_POREP_ID_V1_2_0, ApiVersion::V1_2_0, Vec::new()),
(
ARBITRARY_POREP_ID_V1_2_0,
ApiVersion::V1_2_0,
vec![ApiFeature::SyntheticPoRep],
),
(
ARBITRARY_POREP_ID_V1_2_0,
ApiVersion::V1_2_0,
vec![ApiFeature::NonInteractivePoRep],
),
];

let mut porep_id = [0u8; 32];
porep_id[..8].copy_from_slice(&porep_id_v1.to_le_bytes());
assert!(is_legacy_porep_id(porep_id));
for (porep_id, api_version, features) in test_inputs {
let porep_config = PoRepConfig::new_groth16_with_features(
SECTOR_SIZE_8_MIB,
porep_id,
api_version,
features,
)?;

let porep_config = PoRepConfig::new_groth16(SECTOR_SIZE_512_MIB, porep_id, ApiVersion::V1_0_0);
seal_lifecycle::<SectorShape512MiB>(&porep_config)
seal_lifecycle::<SectorShape8MiB>(&porep_config)?;
}

Ok(())
}

#[cfg(feature = "big-tests")]
#[test]
fn test_seal_lifecycle_512mib_porep_id_v1_top_8_0_0_api_v1_1() -> Result<()> {
use filecoin_proofs::{SectorShape512MiB, SECTOR_SIZE_512_MIB};
let porep_id_v1_1: u64 = 7; // This is a RegisteredSealProof value
fn test_seal_lifecycle_512mib_base_8() -> Result<()> {
let test_inputs = vec![
(ARBITRARY_POREP_ID_V1_0_0, ApiVersion::V1_0_0, Vec::new()),
(ARBITRARY_POREP_ID_V1_1_0, ApiVersion::V1_1_0, Vec::new()),
(ARBITRARY_POREP_ID_V1_2_0, ApiVersion::V1_2_0, Vec::new()),
(
ARBITRARY_POREP_ID_V1_2_0,
ApiVersion::V1_2_0,
vec![ApiFeature::SyntheticPoRep],
),
(
ARBITRARY_POREP_ID_V1_2_0,
ApiVersion::V1_2_0,
vec![ApiFeature::NonInteractivePoRep],
),
];

let mut porep_id = [0u8; 32];
porep_id[..8].copy_from_slice(&porep_id_v1_1.to_le_bytes());
assert!(!is_legacy_porep_id(porep_id));
for (porep_id, api_version, features) in test_inputs {
let porep_config = PoRepConfig::new_groth16_with_features(
SECTOR_SIZE_512_MIB,
porep_id,
api_version,
features,
)?;

seal_lifecycle::<SectorShape512MiB>(&porep_config)?;
}

let porep_config = PoRepConfig::new_groth16(SECTOR_SIZE_512_MIB, porep_id, ApiVersion::V1_1_0);
seal_lifecycle::<SectorShape512MiB>(&porep_config)
Ok(())
}

#[cfg(feature = "big-tests")]
Expand Down Expand Up @@ -962,6 +1006,15 @@ fn aggregate_seal_proofs<Tree: 'static + MerkleTreeTrait>(
);

for aggregate_version in aggregate_versions {
info!(
"Aggregating {} seal proofs with ApiVersion {}, Snarkpack{}, Features {:?}, and PoRep ID {:?}",
num_proofs_to_aggregate,
porep_config.api_version,
aggregate_version,
porep_config.api_features,
porep_config.porep_id
);

let mut commit_outputs = Vec::with_capacity(num_proofs_to_aggregate);
let mut commit_inputs = Vec::with_capacity(num_proofs_to_aggregate);
let mut seeds = Vec::with_capacity(num_proofs_to_aggregate);
Expand Down Expand Up @@ -2224,6 +2277,18 @@ fn proof_and_unseal<Tree: 'static + MerkleTreeTrait>(
aggregation_enabled,
)?;

// For regression suite only -- persist seal proof and everything required for the verify here
#[cfg(feature = "persist-regression-proofs")]
persist_generated_proof_for_regression_testing::<Tree>(
config,
prover_id,
sector_id,
ticket,
seed,
&pre_commit_output,
&commit_output,
)?;

unseal::<Tree>(
config,
cache_dir_path,
Expand Down Expand Up @@ -2283,7 +2348,7 @@ fn create_seal<R: Rng, Tree: 'static + MerkleTreeTrait>(
)?;
compare_trees::<Tree>(&tree_r_last_dir, &cache_dir, CacheKey::CommRLastTree)?;

// Check if creating only the tree_r generates the same output as the full pre commit phase 2
// Check if creating only the tree_c generates the same output as the full pre commit phase 2
// process.
let tree_c_dir = tempdir().expect("failed to create temp dir");
generate_tree_c::<_, _, Tree>(
Expand Down
Loading

0 comments on commit be65d20

Please sign in to comment.