Skip to content

Commit

Permalink
fix: support multiple partitions in PoRep (#752)
Browse files Browse the repository at this point in the history
Co-authored-by: José Duarte <[email protected]>
  • Loading branch information
th7nder and jmg-duarte authored Feb 17, 2025
1 parent fa3873a commit c45ca8e
Show file tree
Hide file tree
Showing 18 changed files with 133 additions and 56 deletions.
11 changes: 9 additions & 2 deletions pallets/market/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,13 +343,20 @@ mod benchmarks {
// Run to 11 to enter pre-commit period
run_to_block::<T>(11);

let proofs = {
// can't use bounded_vec![] in benchmarks
let mut proofs = BoundedVec::new();
// Empty proof is considered valid under the DummyProofVerifier
proofs.try_push(BoundedVec::new()).unwrap();
proofs
};

// Similar pattern to before
(0..n)
// Create ProveCommitSectors from the `n` "index"
.map(|n| ProveCommitSector {
sector_number: n.try_into().unwrap(),
// Empty proof is considered valid under the DummyProofVerifier
proof: BoundedVec::new(),
proofs: proofs.clone(),
})
// Chunk into MAX_SECTORS_PER_CALL due to the cfg
.chunks(MAX_SECTORS_PER_CALL as usize)
Expand Down
45 changes: 30 additions & 15 deletions pallets/proofs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,28 +141,43 @@ pub mod pallet {
sector: SectorNumber,
ticket: Ticket,
seed: Ticket,
proof: BoundedVec<u8, ConstU32<MAX_SEAL_PROOF_BYTES>>,
proofs: BoundedVec<
BoundedVec<u8, ConstU32<MAX_SEAL_PROOF_BYTES>>,
ConstU32<MAX_PROOFS_PER_BLOCK>,
>,
) -> DispatchResult {
let proof_len = proof.len();
ensure!(proof_len >= seal_proof.proof_size(), {
log::error!(
target: LOG_TARGET,
"PoRep proof submission does not contain enough bytes. Expected minimum length is {} got {}",
seal_proof.proof_size(), proof_len
);
Error::<T>::InvalidPoRepProof
});
let proof = Proof::<Bls12>::decode(&mut proof.as_slice()).map_err(|e| {
log::error!(target: LOG_TARGET, "failed to parse PoRep proof {:?}", e);
Error::<T>::Conversion
})?;
let mut parsed_proofs = BoundedVec::new();
for proof in proofs.iter() {
let proof_len = proof.len();
ensure!(proof_len >= seal_proof.proof_size(), {
log::error!(
target: LOG_TARGET,
"PoRep proof submission does not contain enough bytes. Expected minimum length is {} got {}",
seal_proof.proof_size(), proof_len
);
Error::<T>::InvalidPoRepProof
});
let proof = Proof::<Bls12>::decode(&mut proof.as_slice()).map_err(|e| {
log::error!(target: LOG_TARGET, "failed to parse PoRep proof {:?}", e);
Error::<T>::Conversion
})?;

parsed_proofs.try_push(proof).expect("internal (porep::ProofScheme) and external (ProofVerification) apis have the same limits on number of proofs");
}
let proof_scheme = porep::ProofScheme::setup(seal_proof);

let vkey = PoRepVerifyingKey::<T>::get().ok_or(Error::<T>::MissingPoRepVerifyingKey)?;
log::info!(target: LOG_TARGET, "Verifying PoRep proof for sector: {}...", sector);
proof_scheme
.verify(
&comm_r, &comm_d, &prover_id, sector, &ticket, &seed, vkey, &proof,
&comm_r,
&comm_d,
&prover_id,
sector,
&ticket,
&seed,
vkey,
parsed_proofs,
)
.map_err(Into::<Error<T>>::into)?;

Expand Down
8 changes: 8 additions & 0 deletions pallets/proofs/src/porep/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct Config {
porep_id: PoRepID,
nodes: usize,
challenges: InteractiveChallenges,
required_partitions: usize,
}

/// References:
Expand Down Expand Up @@ -71,6 +72,7 @@ impl Config {
// PRE-COND: sector size must be divisible by 32
nodes: (seal_proof.sector_size().bytes() / 32) as usize,
challenges: InteractiveChallenges::new(partitions, minimum_challenges(seal_proof)),
required_partitions: partitions,
}
}

Expand All @@ -88,6 +90,12 @@ impl Config {
pub fn challenges(&self, leaves: usize, replica_id: &Fr, seed: &[u8; 32], k: u8) -> Vec<usize> {
self.challenges.derive(leaves, replica_id, seed, k)
}

/// Expected number of partitions for given PoRep.
/// 1 partition == 1 proof.
pub fn required_partitions(&self) -> usize {
self.required_partitions
}
}

/// Reference:
Expand Down
29 changes: 26 additions & 3 deletions pallets/proofs/src/porep/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
mod config;

use config::{Config, PoRepID};
use frame_support::pallet_prelude::*;
use primitives::{
commitment::RawCommitment,
proofs::{ProverId, RegisteredSealProof, Ticket},
sector::SectorNumber,
MAX_PROOFS_PER_BLOCK,
};
use sha2::{Digest, Sha256};

Expand All @@ -21,6 +23,8 @@ use crate::{
vec, Error, Vec,
};

const LOG_TARGET: &'static str = "runtime::proofs::porep";

/// A unique 32-byte ID assigned to each distinct replica.
/// Replication is the entire process by which a sector is uniquely encoded into a replica.
pub type ReplicaId = Fr;
Expand Down Expand Up @@ -89,6 +93,8 @@ pub enum ProofError {
InvalidVerifyingKey,
/// Returned in case of failed conversion, i.e. in `bytes_into_fr()`.
Conversion,
/// When supplied number of proofs doesn't match required number of proofs (partitions).
InvalidNumberOfProofs,
}

impl From<VerificationError> for ProofError {
Expand All @@ -106,15 +112,18 @@ impl<T> From<ProofError> for Error<T> {
ProofError::InvalidProof => Error::<T>::InvalidPoRepProof,
ProofError::InvalidVerifyingKey => Error::<T>::InvalidVerifyingKey,
ProofError::Conversion => Error::<T>::Conversion,
ProofError::InvalidNumberOfProofs => Error::<T>::InvalidPoRepProof,
}
}
}

#[derive(Clone)]
pub struct Tau {
comm_d: Fr,
comm_r: Fr,
}

#[derive(Clone)]
pub struct PublicInputs {
replica_id: ReplicaId,
tau: Tau,
Expand Down Expand Up @@ -145,11 +154,18 @@ impl ProofScheme {
ticket: &Ticket,
seed: &Ticket,
vk: VerifyingKey<Bls12>,
proof: &Proof<Bls12>,
proofs: BoundedVec<Proof<Bls12>, ConstU32<MAX_PROOFS_PER_BLOCK>>,
) -> Result<(), ProofError> {
let comm_d_fr = fr32::bytes_into_fr(comm_d).map_err(|_| ProofError::Conversion)?;
let comm_r_fr = fr32::bytes_into_fr(comm_r).map_err(|_| ProofError::Conversion)?;

// Proof per partition
if proofs.len() != self.config.required_partitions() {
log::error!(target: LOG_TARGET, "Expected {} proofs (1 per partition) got {} proofs",
self.config.required_partitions(), proofs.len());
return Err(ProofError::InvalidNumberOfProofs);
}

let replica_id = self.generate_replica_id(prover_id, sector, ticket, comm_d);
let public_inputs = PublicInputs {
replica_id,
Expand All @@ -160,10 +176,17 @@ impl ProofScheme {
seed: *seed,
};

let public_inputs = self.generate_public_inputs(public_inputs, None)?;
let pvk = prepare_verifying_key(vk);

verify_proof(&pvk, proof, public_inputs.as_slice()).map_err(Into::<ProofError>::into)
for partition_index in 0..proofs.len() {
let inputs =
self.generate_public_inputs(public_inputs.clone(), Some(partition_index))?;
verify_proof(&pvk, &proofs[partition_index], inputs.as_slice()).inspect_err(|_| {
log::error!(target: LOG_TARGET, "failed to verify partition {}", partition_index);
})?;
}

Ok(())
}

/// References:
Expand Down
3 changes: 1 addition & 2 deletions pallets/proofs/src/post/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ impl ProofScheme {
challenge_hasher.update(&u64::from(sector.id).to_le_bytes()[..]);

for n in 0..self.config.challenges_per_sector {
// let sector_index =
// partition_index * self.config.challenged_sectors_per_partition + i;
// https://github.com/filecoin-project/rust-fil-proofs/blob/8e96f1de6ca8468f5308773c3706c1a25509cf95/storage-proofs-post/src/fallback/utils.rs#L14
let challenge_index = n as u64;
let challenged_leaf =
self.generate_leaf_challenge_inner(challenge_hasher.clone(), challenge_index);
Expand Down
7 changes: 5 additions & 2 deletions pallets/proofs/src/tests/porep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use primitives::{
};
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;
use sp_core::bounded_vec;
use sp_runtime::BoundedVec;

use crate::{mock::*, tests::TEST_SEED, Error, PoRepVerifyingKey};
Expand Down Expand Up @@ -54,7 +55,9 @@ fn verification_invalid_verifyingkey() {
sector,
ticket,
seed,
BoundedVec::try_from(proof_bytes).expect("proof bytes should be valid"),
bounded_vec![
BoundedVec::try_from(proof_bytes).expect("proof bytes should be valid")
],
),
Error::<Test>::InvalidVerifyingKey,
);
Expand Down Expand Up @@ -82,7 +85,7 @@ fn porep_verification_succeeds() {
sector,
ticket,
seed,
BoundedVec::try_from(proof_bytes).expect("proof bytes should be valid"),
bounded_vec![BoundedVec::try_from(proof_bytes).expect("proof bytes should be valid")],
));
});
}
Expand Down
15 changes: 9 additions & 6 deletions pallets/storage-provider/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ pub mod pallet {
proofs::{derive_prover_id, PublicReplicaInfo, RegisteredPoStProof},
randomness::{draw_randomness, AuthorVrfHistory, DomainSeparationTag},
sector::{ProveCommitSector, SectorNumber, SectorPreCommitInfo},
PartitionNumber, MAX_PARTITIONS_PER_DEADLINE, MAX_SEAL_PROOF_BYTES, MAX_SECTORS,
MAX_SECTORS_PER_CALL,
PartitionNumber, MAX_PARTITIONS_PER_DEADLINE, MAX_PROOFS_PER_BLOCK, MAX_SEAL_PROOF_BYTES,
MAX_SECTORS, MAX_SECTORS_PER_CALL,
};
use scale_info::TypeInfo;
use sp_arithmetic::traits::Zero;
Expand Down Expand Up @@ -601,7 +601,7 @@ pub mod pallet {
});

// Validate the proof
validate_seal_proof::<T>(&owner, &precommit, sector.proof)?;
validate_seal_proof::<T>(&owner, &precommit, sector.proofs)?;

// Sector deals that will be activated after the sector is
// successfully proven.
Expand Down Expand Up @@ -1634,12 +1634,15 @@ pub mod pallet {
fn validate_seal_proof<T: Config>(
owner: &T::AccountId,
precommit: &SectorPreCommitOnChainInfo<BalanceOf<T>, BlockNumberFor<T>>,
proof: BoundedVec<u8, ConstU32<MAX_SEAL_PROOF_BYTES>>,
proofs: BoundedVec<
BoundedVec<u8, ConstU32<MAX_SEAL_PROOF_BYTES>>,
ConstU32<MAX_PROOFS_PER_BLOCK>,
>,
) -> Result<(), DispatchError> {
let max_proof_size = precommit.info.seal_proof.proof_size();

// Check proof size
if proof.len() > max_proof_size {
if let Some(proof) = proofs.iter().filter(|p| p.len() > max_proof_size).nth(0) {
log::error!(target: LOG_TARGET, "sector proof size {} exceeds max {}", proof.len(), max_proof_size);
return Err(Error::<T>::InvalidProof)?;
}
Expand Down Expand Up @@ -1692,7 +1695,7 @@ pub mod pallet {
precommit.info.sector_number,
precommit.seal_randomness,
interactive_randomness,
proof,
proofs,
)
}

Expand Down
4 changes: 2 additions & 2 deletions pallets/storage-provider/src/tests/declare_faults.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ pub(crate) fn setup_sp_with_one_sector(storage_provider: &str, storage_client: &
// Prove commit sector
let sector = ProveCommitSector {
sector_number,
proof: bounded_vec![0xd, 0xe, 0xa, 0xd],
proofs: bounded_vec![bounded_vec![0xd, 0xe, 0xa, 0xd]],
};

assert_ok!(StorageProvider::prove_commit_sectors(
Expand Down Expand Up @@ -539,7 +539,7 @@ pub(crate) fn setup_sp_with_many_sectors_multiple_partitions(
// Prove commit sector
let sector = ProveCommitSector {
sector_number,
proof: bounded_vec![0xb, 0xe, 0xe, 0xf],
proofs: bounded_vec![bounded_vec![0xb, 0xe, 0xe, 0xf]],
};

assert_ok!(StorageProvider::prove_commit_sectors(
Expand Down
2 changes: 1 addition & 1 deletion pallets/storage-provider/src/tests/post_hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ fn precommit_and_prove(storage_provider: &'static str, deal_id: DealId, sector_n
RuntimeOrigin::signed(account(storage_provider)),
bounded_vec![ProveCommitSector {
sector_number,
proof: bounded_vec![0xde],
proofs: bounded_vec![bounded_vec![0xde]],
}],
)
.unwrap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ fn pre_commit_hook_slashed_deal() {
RuntimeOrigin::signed(account(storage_provider)),
bounded_vec![ProveCommitSector {
sector_number: 2.into(),
proof: bounded_vec![0xde],
proofs: bounded_vec![bounded_vec![0xde]],
}],
)
.unwrap();
Expand Down
12 changes: 6 additions & 6 deletions pallets/storage-provider/src/tests/prove_commit_sectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fn successfully_prove_sector() {
// Test prove commits
let sector = ProveCommitSector {
sector_number,
proof: bounded_vec![0xd, 0xe, 0xa, 0xd],
proofs: bounded_vec![bounded_vec![0xd, 0xe, 0xa, 0xd]],
};

// Run to the block, where we will be able to prove commit the sector.
Expand Down Expand Up @@ -157,7 +157,7 @@ fn successfully_prove_multiple_sectors() {
sectors
.try_push(ProveCommitSector {
sector_number,
proof: bounded_vec![0xd, 0xe, 0xa, 0xd],
proofs: bounded_vec![bounded_vec![0xd, 0xe, 0xa, 0xd]],
})
.expect("BoundedVec should fit all 6 elements");
expected_sector_results
Expand Down Expand Up @@ -297,7 +297,7 @@ fn successfully_prove_after_period_start_and_check_mutability() {
sectors
.try_push(ProveCommitSector {
sector_number,
proof: bounded_vec![0xd, 0xe, 0xa, 0xd],
proofs: bounded_vec![bounded_vec![0xd, 0xe, 0xa, 0xd]],
})
.expect("BoundedVec should fit all elements");
expected_sector_results
Expand All @@ -322,7 +322,7 @@ fn fails_storage_provider_not_found() {
// Test prove commits
let sector = ProveCommitSector {
sector_number: 1.into(),
proof: bounded_vec![0xd, 0xe, 0xa, 0xd],
proofs: bounded_vec![bounded_vec![0xd, 0xe, 0xa, 0xd]],
};

assert_noop!(
Expand All @@ -346,7 +346,7 @@ fn fails_storage_precommit_missing() {
// Test prove commits
let sector = ProveCommitSector {
sector_number: 1.into(),
proof: bounded_vec![0xd, 0xe, 0xa, 0xd],
proofs: bounded_vec![bounded_vec![0xd, 0xe, 0xa, 0xd]],
};

assert_noop!(
Expand Down Expand Up @@ -394,7 +394,7 @@ fn fails_prove_commit_after_deadline() {
// Test prove commits
let sector = ProveCommitSector {
sector_number,
proof: bounded_vec![0xd, 0xe, 0xa, 0xd],
proofs: bounded_vec![bounded_vec![0xd, 0xe, 0xa, 0xd]],
};

run_to_block(proving_at_block_number);
Expand Down
2 changes: 1 addition & 1 deletion pallets/storage-provider/src/tests/submit_windowed_post.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fn setup() {
// Prove commit sector
let sector = ProveCommitSector {
sector_number,
proof: bounded_vec![0xd, 0xe, 0xa, 0xd],
proofs: bounded_vec![bounded_vec![0xd, 0xe, 0xa, 0xd]],
};

assert_ok!(StorageProvider::prove_commit_sectors(
Expand Down
5 changes: 4 additions & 1 deletion primitives/src/pallets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ pub trait ProofVerification {
sector: SectorNumber,
ticket: Ticket,
seed: Ticket,
proof: BoundedVec<u8, ConstU32<MAX_SEAL_PROOF_BYTES>>,
proofs: BoundedVec<
BoundedVec<u8, ConstU32<MAX_SEAL_PROOF_BYTES>>,
ConstU32<MAX_PROOFS_PER_BLOCK>,
>,
) -> DispatchResult;

fn verify_post(
Expand Down
Loading

0 comments on commit c45ca8e

Please sign in to comment.