From 0155a31d1f4838e2b80245b22bcc9b3a2520686b Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 25 Aug 2020 19:53:21 -0700 Subject: [PATCH 1/2] Fix PoSt with bad sectors "skipped" sectors must be replaced with a substitute "good" sector, or the entire partition must be skipped. They should not just be omitted. This patch also fixes the test to verify the _entire_ proof instead of just verifying that the proof includes the correct sectors. --- api/test/window_post.go | 4 ++ extern/sector-storage/mock/mock.go | 61 ++++++++---------------------- storage/wdpost_run.go | 38 ++++++++++++++----- 3 files changed, 49 insertions(+), 54 deletions(-) diff --git a/api/test/window_post.go b/api/test/window_post.go index 7dd4a0742..2171324fc 100644 --- a/api/test/window_post.go +++ b/api/test/window_post.go @@ -216,6 +216,10 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector sn, err := parts[0].Sectors.First() require.NoError(t, err) + all, err := parts[0].Sectors.All(2) + require.NoError(t, err) + fmt.Println("the sectors", all) + s = abi.SectorID{ Miner: abi.ActorID(mid), Number: abi.SectorNumber(sn), diff --git a/extern/sector-storage/mock/mock.go b/extern/sector-storage/mock/mock.go index e3fcc3f5b..4afe5f096 100644 --- a/extern/sector-storage/mock/mock.go +++ b/extern/sector-storage/mock/mock.go @@ -3,12 +3,12 @@ package mock import ( "bytes" "context" + "crypto/sha256" "fmt" "io" "math/rand" "sync" - "github.com/filecoin-project/go-bitfield" commcid "github.com/filecoin-project/go-fil-commcid" "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-storage/storage" @@ -291,32 +291,29 @@ func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorI return generateFakePoSt(si, abi.RegisteredSealProof.RegisteredWindowPoStProof, randomness), skipped, nil } -func generateFakePoSt(sectorInfo []abi.SectorInfo, rpt func(abi.RegisteredSealProof) (abi.RegisteredPoStProof, error), randomness abi.PoStRandomness) []abi.PoStProof { - sectors := bitfield.New() +func generateFakePoStProof(sectorInfo []abi.SectorInfo, randomness abi.PoStRandomness) []byte { + hasher := sha256.New() + _, _ = hasher.Write(randomness) for _, info := range sectorInfo { - sectors.Set(uint64(info.SectorNumber)) + err := info.MarshalCBOR(hasher) + if err != nil { + panic(err) + } } + return hasher.Sum(nil) +} + +func generateFakePoSt(sectorInfo []abi.SectorInfo, rpt func(abi.RegisteredSealProof) (abi.RegisteredPoStProof, error), randomness abi.PoStRandomness) []abi.PoStProof { wp, err := rpt(sectorInfo[0].SealProof) if err != nil { panic(err) } - var proofBuf bytes.Buffer - - _, err = proofBuf.Write(randomness) - if err != nil { - panic(err) - } - - if err := sectors.MarshalCBOR(&proofBuf); err != nil { - panic(err) - } - return []abi.PoStProof{ { PoStProof: wp, - ProofBytes: proofBuf.Bytes(), + ProofBytes: generateFakePoStProof(sectorInfo, randomness), }, } } @@ -412,36 +409,10 @@ func (m mockVerif) VerifyWindowPoSt(ctx context.Context, info abi.WindowPoStVeri proof := info.Proofs[0] - if !bytes.Equal(proof.ProofBytes[:len(info.Randomness)], info.Randomness) { - return false, xerrors.Errorf("bad randomness") + expected := generateFakePoStProof(info.ChallengedSectors, info.Randomness) + if !bytes.Equal(proof.ProofBytes, expected) { + return false, xerrors.Errorf("bad proof") } - - sectors := bitfield.New() - if err := sectors.UnmarshalCBOR(bytes.NewReader(proof.ProofBytes[len(info.Randomness):])); err != nil { - return false, xerrors.Errorf("unmarshaling sectors bitfield from \"proof\": %w", err) - } - - challenged := bitfield.New() - for _, sector := range info.ChallengedSectors { - challenged.Set(uint64(sector.SectorNumber)) - } - - { - b1, err := sectors.MarshalJSON() - if err != nil { - return false, err - } - - b2, err := challenged.MarshalJSON() - if err != nil { - return false, err - } - - if !bytes.Equal(b1, b2) { - return false, xerrors.Errorf("proven and challenged sector sets didn't match: %s != %s", string(b1), string(b2)) - } - } - return true, nil } diff --git a/storage/wdpost_run.go b/storage/wdpost_run.go index 821c23cd7..2e0ed1c84 100644 --- a/storage/wdpost_run.go +++ b/storage/wdpost_run.go @@ -366,7 +366,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di miner.DeadlineInfo skipCount += sc - ssi, err := s.sectorInfo(ctx, good, ts) + ssi, err := s.sectorsForProof(ctx, good, partition.Sectors, ts) if err != nil { return nil, xerrors.Errorf("getting sorted sector info: %w", err) } @@ -399,8 +399,6 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di miner.DeadlineInfo tsStart := build.Clock.Now() - log.Infow("generating windowPost", "sectors", len(sinfos)) - mid, err := address.IDFromAddress(s.actor) if err != nil { return nil, err @@ -436,22 +434,44 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di miner.DeadlineInfo return params, nil } -func (s *WindowPoStScheduler) sectorInfo(ctx context.Context, deadlineSectors abi.BitField, ts *types.TipSet) ([]abi.SectorInfo, error) { - sset, err := s.api.StateMinerSectors(ctx, s.actor, &deadlineSectors, false, ts.Key()) +func (s *WindowPoStScheduler) sectorsForProof(ctx context.Context, goodSectors, allSectors abi.BitField, ts *types.TipSet) ([]abi.SectorInfo, error) { + sset, err := s.api.StateMinerSectors(ctx, s.actor, &goodSectors, false, ts.Key()) if err != nil { return nil, err } - sbsi := make([]abi.SectorInfo, len(sset)) - for k, sector := range sset { - sbsi[k] = abi.SectorInfo{ + if len(sset) == 0 { + return nil, nil + } + + substitute := abi.SectorInfo{ + SectorNumber: sset[0].ID, + SealedCID: sset[0].Info.SealedCID, + SealProof: sset[0].Info.SealProof, + } + + sectorByID := make(map[uint64]abi.SectorInfo, len(sset)) + for _, sector := range sset { + sectorByID[uint64(sector.ID)] = abi.SectorInfo{ SectorNumber: sector.ID, SealedCID: sector.Info.SealedCID, SealProof: sector.Info.SealProof, } } - return sbsi, nil + proofSectors := make([]abi.SectorInfo, 0, len(sset)) + if err := allSectors.ForEach(func(sectorNo uint64) error { + if info, found := sectorByID[sectorNo]; found { + proofSectors = append(proofSectors, info) + } else { + proofSectors = append(proofSectors, substitute) + } + return nil + }); err != nil { + return nil, xerrors.Errorf("iterating partition sector bitmap: %w", err) + } + + return proofSectors, nil } func (s *WindowPoStScheduler) submitPost(ctx context.Context, proof *miner.SubmitWindowedPoStParams) error { From f8a14184c7f8975a022e0a26c3eac553d5d27cca Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Wed, 26 Aug 2020 10:05:03 -0700 Subject: [PATCH 2/2] Fix lint issue --- api/test/util.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/api/test/util.go b/api/test/util.go index 7d2e9e95b..88e0e0fe6 100644 --- a/api/test/util.go +++ b/api/test/util.go @@ -41,13 +41,16 @@ func MineUntilBlock(ctx context.Context, t *testing.T, sn TestStorageNode, cb fu var success bool var err error wait := make(chan struct{}) - sn.MineOne(ctx, miner.MineReq{ + mineErr := sn.MineOne(ctx, miner.MineReq{ Done: func(win bool, e error) { success = win err = e wait <- struct{}{} }, }) + if mineErr != nil { + t.Fatal(mineErr) + } <-wait if err != nil { t.Fatal(err)