Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(storage-proofs): implement rational post #763

Merged
merged 31 commits into from
Aug 27, 2019

Conversation

dignifiedquire
Copy link
Contributor

@dignifiedquire dignifiedquire commented Jul 29, 2019

storage-proofs/src/circuit/rational_post.rs Outdated Show resolved Hide resolved
storage-proofs/src/rational_post.rs Outdated Show resolved Hide resolved
storage-proofs/src/rational_post.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@laser laser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BLOCKING: This PR needs to generate and publish new Groth parameters.

Note: Breaking API Changes

  • generate_post challenge_seed parameter becomes &ChallengeSeed
  • generate_post now accepts &[u64] for faults
  • generate_post has new return type
  • verify_post now accepts &[u8] instead of Vec<Vec<u8>> for proofs
  • verify_post challenge_seed parameter becomes &ChallengeSeed
  • verify_post now accepts &[u64] for faults
  • SectorClass drops PoStProofPartitions


let commitments: Vec<_> = challenges
.iter()
.map(|c| commitments_all[c.sector as usize])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BLOCKING: Please use Vec::get and early-return on a None instead of indexing into the thing directly (which will panic if there is no value corresponding to the provided index).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Counterpoint: derive_challenges had damn well better make sure c.sector is in range, and if it's not then we risk generating an invalid PoSt and need the moral equivalent of a panic (although I agree that should be caught and handled gracefully at the API boundary).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have any panic-recovery tooling yet, so this will unwind the stack and crash the Filecoin node. Until we build those tools, please avoid using panics.

filecoin-proofs/src/api.rs Outdated Show resolved Hide resolved
filecoin-proofs/src/api.rs Outdated Show resolved Hide resolved
filecoin-proofs/src/api.rs Outdated Show resolved Hide resolved
filecoin-proofs/src/api.rs Outdated Show resolved Hide resolved
filecoin-proofs/src/api.rs Outdated Show resolved Hide resolved
storage-proofs/src/rational_post.rs Outdated Show resolved Hide resolved
storage-proofs/src/rational_post.rs Outdated Show resolved Hide resolved
storage-proofs/src/rational_post.rs Outdated Show resolved Hide resolved
filecoin-proofs/src/api.rs Outdated Show resolved Hide resolved
filecoin-proofs/src/api.rs Outdated Show resolved Hide resolved
porcuquine
porcuquine previously approved these changes Aug 23, 2019
Copy link
Collaborator

@porcuquine porcuquine left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good stuff, @dignifiedquire. Much simpler now…

filecoin-proofs/src/api.rs Show resolved Hide resolved
filecoin-proofs/src/api.rs Outdated Show resolved Hide resolved

let commitments: Vec<_> = challenges
.iter()
.map(|c| commitments_all[c.sector as usize])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Counterpoint: derive_challenges had damn well better make sure c.sector is in range, and if it's not then we risk generating an invalid PoSt and need the moral equivalent of a panic (although I agree that should be caught and handled gracefully at the API boundary).

)
.unwrap()
} else {
panic!("faults are not yet supported")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should give ReplicaInfo (or whatever you call it) a method which can convert it into a tree. We should pass those as private inputs, then only treeify them if the sector is challenged. This assumes there will be enough time to do that. This is a whole question I'm trying to get answers to now and will create an issue if necessary.

In any case, we can't hold all the trees in memory (and I think go-filecoin) is currently blowing up because of this.

filecoin-proofs/src/api.rs Show resolved Hide resolved

pub fn to_vec(&self) -> Vec<u8> {
let mut out = Vec::new();
self.write(&mut out).expect("known allocation target");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you defile the holy MultiProof so?

@dignifiedquire
Copy link
Contributor Author

BLOCKING: This PR needs to generate and publish new Groth parameters.

yes, will do once this PR is fully settled and approved

filecoin-proofs/src/api.rs Outdated Show resolved Hide resolved
filecoin-proofs/src/api.rs Outdated Show resolved Hide resolved
let challenged_replicas: Vec<_> = challenges
.iter()
.map(|c| {
if let Some(replica) = replicas.get(c.sector as usize) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BLOCKING: replicas.get(c.sector as usize) is going to index into replicas by sector id. replicas is a Vec (i.e. not sector id-indexed data structure).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do I get the sector id from the the replica then?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need to extend ReplicaInfo to include this information, e.g.

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ReplicaInfo {
    /// Path to the replica.
    access: String,
    /// The replica commitment.
    commitment: Commitment,

    sector_id: SectorId
}

Copy link
Contributor

@laser laser Aug 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should pause this thread until we're all on the same page regarding whether or not GeneratePoSt should accept a SectorSet (a sector id-indexed map) or an ordered list of sector ids.

use byteorder::ByteOrder;

/// An ordered set of `SectorId`s.
pub type SectorSet = BTreeSet<SectorId>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Change the name of this type to something other than SectorSet. SectorIdSet would be fine by me.

Rationale: The protocol already specifies SectorSet to be a map from sector id to replica commitment. Your type is not a map from sector id to replica commitment; I am certain that the name collision will cause some confusion in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to OrderedSectorSet

filecoin-proofs/src/api.rs Outdated Show resolved Hide resolved
filecoin-proofs/src/api.rs Outdated Show resolved Hide resolved
Copy link
Collaborator

@porcuquine porcuquine left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BLOCKING: Please look into my questions about apparently conflating SectorId with offset, even after changes to disentangle them. I made comments in a number of places to highlight the issue, and they should be taken as a group.

let challenged_sector = u64::from(challenge.sector);
let challenged_leaf = challenge.leaf;

let tree = priv_inputs.trees[challenged_sector as usize];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

challenged_sector, which is the challenge.sector, seems to be used as an index into the trees here, but the type of challenge.Sector is SectorId. This seems like a mismatch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

storage-proofs/src/rational_post.rs Show resolved Hide resolved
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Challenge {
// The index of the sector into the sector list.
pub sector: SectorId,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It it the index, or is it the Id?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ID, forgot to update the comment

storage-proofs/src/rational_post.rs Show resolved Hide resolved
.iter()
.zip(pub_inputs.commitments.iter())
.map(|(challenge, commitment)| {
let challenged_sector = u64::from(challenge.sector);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you turning a SectorId into a u64? It seems like this is defeating the type system and allowing you to look up a tree in an array by the integer value of its SectorId.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

faults.insert(1.into());
let mut sectors = SectorSet::new();
sectors.insert(0.into());
sectors.insert(1.into());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this test needs to be made more robust. It's not catching the fact that we're indexing into the trees using the SectorId and not the calculated challenge offset.

I believe the test will break and expose this if you change line 297 to read sectors.insert(2.into());.

We should also go further and add at least one more non-faulted sector and ensure that the test specifically validates that it has been selected correctly. In generally, we should avoid only inserting sectors whose SectorIds are consecutive, starting from 0 — since this is very special case in which SectorId and offset into an ordered set happen to be identical.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

laser
laser previously approved these changes Aug 27, 2019
Copy link
Contributor

@laser laser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, but your tests are busted.

porcuquine
porcuquine previously approved these changes Aug 27, 2019
Copy link
Collaborator

@porcuquine porcuquine left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Some non-blocking thoughts to consider for future iterations (or not).

/// The replica commitment.
commitment: Commitment,
/// Is this sector marked as a fault?
is_fault: bool,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessary, but it might be nice to make this whole type be an Enum with faulty and non-faulty variants — the faulty version omitting the access. This would make it impossible to generate merkle trees from faulty sectors, potentially heading off some unpleasant failure modes we might accidentally stumble into if it's possible to do so.


if let Some(tree) = priv_inputs.trees.get(&challenge.sector) {
if commitment != &tree.root() {
return Err(Error::InvalidCommitment);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this is the right name for the error here. The commitment is valid by definition, right?

@dignifiedquire dignifiedquire merged commit d2b39cc into master Aug 27, 2019
@dignifiedquire dignifiedquire deleted the feat/rational-post branch August 27, 2019 20:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants