persist deal schedule to piece data for pre-commit sector expiry

This commit is contained in:
laser 2020-04-07 14:44:33 -07:00
parent 5326cb55b3
commit de07fe8aaf
9 changed files with 403 additions and 156 deletions

View File

@ -13,12 +13,125 @@ import (
var _ = xerrors.Errorf var _ = xerrors.Errorf
func (t *Piece) MarshalCBOR(w io.Writer) error { func (t *PieceWithOptionalDealInfo) MarshalCBOR(w io.Writer) error {
if t == nil { if t == nil {
_, err := w.Write(cbg.CborNull) _, err := w.Write(cbg.CborNull)
return err return err
} }
if _, err := w.Write([]byte{163}); err != nil { if _, err := w.Write([]byte{162}); err != nil {
return err
}
// t.Piece (abi.PieceInfo) (struct)
if len("Piece") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"Piece\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("Piece")))); err != nil {
return err
}
if _, err := w.Write([]byte("Piece")); err != nil {
return err
}
if err := t.Piece.MarshalCBOR(w); err != nil {
return err
}
// t.DealInfo (sealing.DealInfo) (struct)
if len("DealInfo") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"DealInfo\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("DealInfo")))); err != nil {
return err
}
if _, err := w.Write([]byte("DealInfo")); err != nil {
return err
}
if err := t.DealInfo.MarshalCBOR(w); err != nil {
return err
}
return nil
}
func (t *PieceWithOptionalDealInfo) UnmarshalCBOR(r io.Reader) error {
br := cbg.GetPeeker(r)
maj, extra, err := cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajMap {
return fmt.Errorf("cbor input should be of type map")
}
if extra > cbg.MaxLength {
return fmt.Errorf("PieceWithOptionalDealInfo: map struct too large (%d)", extra)
}
var name string
n := extra
for i := uint64(0); i < n; i++ {
{
sval, err := cbg.ReadString(br)
if err != nil {
return err
}
name = string(sval)
}
switch name {
// t.Piece (abi.PieceInfo) (struct)
case "Piece":
{
if err := t.Piece.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.Piece: %w", err)
}
}
// t.DealInfo (sealing.DealInfo) (struct)
case "DealInfo":
{
pb, err := br.PeekByte()
if err != nil {
return err
}
if pb == cbg.CborNull[0] {
var nbuf [1]byte
if _, err := br.Read(nbuf[:]); err != nil {
return err
}
} else {
t.DealInfo = new(DealInfo)
if err := t.DealInfo.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.DealInfo pointer: %w", err)
}
}
}
default:
return fmt.Errorf("unknown struct field %d: '%s'", i, name)
}
}
return nil
}
func (t *DealInfo) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write([]byte{162}); err != nil {
return err return err
} }
@ -34,52 +147,29 @@ func (t *Piece) MarshalCBOR(w io.Writer) error {
return err return err
} }
if t.DealID == nil { if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.DealID))); err != nil {
if _, err := w.Write(cbg.CborNull); err != nil {
return err
}
} else {
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(*t.DealID))); err != nil {
return err
}
}
// t.Size (abi.UnpaddedPieceSize) (uint64)
if len("Size") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"Size\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("Size")))); err != nil {
return err
}
if _, err := w.Write([]byte("Size")); err != nil {
return err return err
} }
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Size))); err != nil { // t.DealSchedule (sealing.DealSchedule) (struct)
if len("DealSchedule") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"DealSchedule\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("DealSchedule")))); err != nil {
return err
}
if _, err := w.Write([]byte("DealSchedule")); err != nil {
return err return err
} }
// t.CommP (cid.Cid) (struct) if err := t.DealSchedule.MarshalCBOR(w); err != nil {
if len("CommP") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"CommP\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("CommP")))); err != nil {
return err return err
} }
if _, err := w.Write([]byte("CommP")); err != nil {
return err
}
if err := cbg.WriteCid(w, t.CommP); err != nil {
return xerrors.Errorf("failed to write cid field t.CommP: %w", err)
}
return nil return nil
} }
func (t *Piece) UnmarshalCBOR(r io.Reader) error { func (t *DealInfo) UnmarshalCBOR(r io.Reader) error {
br := cbg.GetPeeker(r) br := cbg.GetPeeker(r)
maj, extra, err := cbg.CborReadHeader(br) maj, extra, err := cbg.CborReadHeader(br)
@ -91,7 +181,7 @@ func (t *Piece) UnmarshalCBOR(r io.Reader) error {
} }
if extra > cbg.MaxLength { if extra > cbg.MaxLength {
return fmt.Errorf("Piece: map struct too large (%d)", extra) return fmt.Errorf("DealInfo: map struct too large (%d)", extra)
} }
var name string var name string
@ -114,55 +204,170 @@ func (t *Piece) UnmarshalCBOR(r io.Reader) error {
{ {
pb, err := br.PeekByte() maj, extra, err = cbg.CborReadHeader(br)
if err != nil { if err != nil {
return err return err
} }
if pb == cbg.CborNull[0] { if maj != cbg.MajUnsignedInt {
var nbuf [1]byte return fmt.Errorf("wrong type for uint64 field")
if _, err := br.Read(nbuf[:]); err != nil { }
t.DealID = abi.DealID(extra)
}
// t.DealSchedule (sealing.DealSchedule) (struct)
case "DealSchedule":
{
if err := t.DealSchedule.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.DealSchedule: %w", err)
}
}
default:
return fmt.Errorf("unknown struct field %d: '%s'", i, name)
}
}
return nil
}
func (t *DealSchedule) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write([]byte{162}); err != nil {
return err
}
// t.StartEpoch (abi.ChainEpoch) (int64)
if len("StartEpoch") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"StartEpoch\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("StartEpoch")))); err != nil {
return err
}
if _, err := w.Write([]byte("StartEpoch")); err != nil {
return err
}
if t.StartEpoch >= 0 {
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.StartEpoch))); err != nil {
return err return err
} }
} else { } else {
maj, extra, err = cbg.CborReadHeader(br) if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.StartEpoch)-1)); err != nil {
return err
}
}
// t.EndEpoch (abi.ChainEpoch) (int64)
if len("EndEpoch") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"EndEpoch\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("EndEpoch")))); err != nil {
return err
}
if _, err := w.Write([]byte("EndEpoch")); err != nil {
return err
}
if t.EndEpoch >= 0 {
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.EndEpoch))); err != nil {
return err
}
} else {
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.EndEpoch)-1)); err != nil {
return err
}
}
return nil
}
func (t *DealSchedule) UnmarshalCBOR(r io.Reader) error {
br := cbg.GetPeeker(r)
maj, extra, err := cbg.CborReadHeader(br)
if err != nil { if err != nil {
return err return err
} }
if maj != cbg.MajUnsignedInt { if maj != cbg.MajMap {
return fmt.Errorf("wrong type for uint64 field") return fmt.Errorf("cbor input should be of type map")
}
typed := abi.DealID(extra)
t.DealID = &typed
} }
if extra > cbg.MaxLength {
return fmt.Errorf("DealSchedule: map struct too large (%d)", extra)
} }
// t.Size (abi.UnpaddedPieceSize) (uint64)
case "Size": var name string
n := extra
for i := uint64(0); i < n; i++ {
{ {
sval, err := cbg.ReadString(br)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil { if err != nil {
return err return err
} }
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.Size = abi.UnpaddedPieceSize(extra)
name = string(sval)
} }
// t.CommP (cid.Cid) (struct)
case "CommP":
switch name {
// t.StartEpoch (abi.ChainEpoch) (int64)
case "StartEpoch":
{ {
maj, extra, err := cbg.CborReadHeader(br)
c, err := cbg.ReadCid(br) var extraI int64
if err != nil { if err != nil {
return xerrors.Errorf("failed to read cid field t.CommP: %w", err) return err
}
switch maj {
case cbg.MajUnsignedInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 positive overflow")
}
case cbg.MajNegativeInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 negative oveflow")
}
extraI = -1 - extraI
default:
return fmt.Errorf("wrong type for int64 field: %d", maj)
} }
t.CommP = c t.StartEpoch = abi.ChainEpoch(extraI)
}
// t.EndEpoch (abi.ChainEpoch) (int64)
case "EndEpoch":
{
maj, extra, err := cbg.CborReadHeader(br)
var extraI int64
if err != nil {
return err
}
switch maj {
case cbg.MajUnsignedInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 positive overflow")
}
case cbg.MajNegativeInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 negative oveflow")
}
extraI = -1 - extraI
default:
return fmt.Errorf("wrong type for int64 field: %d", maj)
}
t.EndEpoch = abi.ChainEpoch(extraI)
} }
default: default:
@ -258,26 +463,26 @@ func (t *SectorInfo) MarshalCBOR(w io.Writer) error {
} }
} }
// t.Pieces ([]sealing.Piece) (slice) // t.PiecesWithOptionalDealInfo ([]sealing.PieceWithOptionalDealInfo) (slice)
if len("Pieces") > cbg.MaxLength { if len("PiecesWithOptionalDealInfo") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"Pieces\" was too long") return xerrors.Errorf("Value in field \"PiecesWithOptionalDealInfo\" was too long")
} }
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("Pieces")))); err != nil { if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("PiecesWithOptionalDealInfo")))); err != nil {
return err return err
} }
if _, err := w.Write([]byte("Pieces")); err != nil { if _, err := w.Write([]byte("PiecesWithOptionalDealInfo")); err != nil {
return err return err
} }
if len(t.Pieces) > cbg.MaxLength { if len(t.PiecesWithOptionalDealInfo) > cbg.MaxLength {
return xerrors.Errorf("Slice value in field t.Pieces was too long") return xerrors.Errorf("Slice value in field t.PiecesWithOptionalDealInfo was too long")
} }
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Pieces)))); err != nil { if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.PiecesWithOptionalDealInfo)))); err != nil {
return err return err
} }
for _, v := range t.Pieces { for _, v := range t.PiecesWithOptionalDealInfo {
if err := v.MarshalCBOR(w); err != nil { if err := v.MarshalCBOR(w); err != nil {
return err return err
} }
@ -692,8 +897,8 @@ func (t *SectorInfo) UnmarshalCBOR(r io.Reader) error {
t.SectorType = abi.RegisteredProof(extraI) t.SectorType = abi.RegisteredProof(extraI)
} }
// t.Pieces ([]sealing.Piece) (slice) // t.PiecesWithOptionalDealInfo ([]sealing.PieceWithOptionalDealInfo) (slice)
case "Pieces": case "PiecesWithOptionalDealInfo":
maj, extra, err = cbg.CborReadHeader(br) maj, extra, err = cbg.CborReadHeader(br)
if err != nil { if err != nil {
@ -701,23 +906,23 @@ func (t *SectorInfo) UnmarshalCBOR(r io.Reader) error {
} }
if extra > cbg.MaxLength { if extra > cbg.MaxLength {
return fmt.Errorf("t.Pieces: array too large (%d)", extra) return fmt.Errorf("t.PiecesWithOptionalDealInfo: array too large (%d)", extra)
} }
if maj != cbg.MajArray { if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array") return fmt.Errorf("expected cbor array")
} }
if extra > 0 { if extra > 0 {
t.Pieces = make([]Piece, extra) t.PiecesWithOptionalDealInfo = make([]PieceWithOptionalDealInfo, extra)
} }
for i := 0; i < int(extra); i++ { for i := 0; i < int(extra); i++ {
var v Piece var v PieceWithOptionalDealInfo
if err := v.UnmarshalCBOR(br); err != nil { if err := v.UnmarshalCBOR(br); err != nil {
return err return err
} }
t.Pieces[i] = v t.PiecesWithOptionalDealInfo[i] = v
} }
// t.TicketValue (abi.SealRandomness) (slice) // t.TicketValue (abi.SealRandomness) (slice)

View File

@ -27,40 +27,38 @@ type ErrExpiredTicket struct{ error }
type ErrBadSeed struct{ error } type ErrBadSeed struct{ error }
type ErrInvalidProof struct{ error } type ErrInvalidProof struct{ error }
// checkPieces validates that:
// - Each piece han a corresponding on chain deal
// - Piece commitments match with on chain deals
// - Piece sizes match
// - Deals aren't expired
func checkPieces(ctx context.Context, si SectorInfo, api SealingAPI) error { func checkPieces(ctx context.Context, si SectorInfo, api SealingAPI) error {
tok, height, err := api.ChainHead(ctx) tok, height, err := api.ChainHead(ctx)
if err != nil { if err != nil {
return &ErrApi{xerrors.Errorf("getting chain head: %w", err)} return &ErrApi{xerrors.Errorf("getting chain head: %w", err)}
} }
for i, piece := range si.Pieces { for i, pdi := range si.PiecesWithOptionalDealInfo {
if piece.DealID == nil { // if no deal is associated with the piece, ensure that we added it as
exp := zerocomm.ZeroPieceCommitment(piece.Size) // filler (i.e. ensure that it has a zero PieceCID)
if piece.CommP != exp { if pdi.DealInfo == nil {
return &ErrInvalidPiece{xerrors.Errorf("deal %d piece %d had non-zero CommP %+v", piece.DealID, i, piece.CommP)} exp := zerocomm.ZeroPieceCommitment(pdi.Piece.Size.Unpadded())
if !pdi.Piece.PieceCID.Equals(exp) {
return &ErrInvalidPiece{xerrors.Errorf("sector %d piece %d had non-zero PieceCID %+v", si.SectorNumber, i, pdi.Piece.PieceCID)}
} }
continue continue
} }
proposal, _, err := api.StateMarketStorageDeal(ctx, *piece.DealID, tok)
proposal, _, err := api.StateMarketStorageDeal(ctx, pdi.DealInfo.DealID, tok)
if err != nil { if err != nil {
return &ErrApi{xerrors.Errorf("getting deal %d for piece %d: %w", piece.DealID, i, err)} return &ErrApi{xerrors.Errorf("getting deal %d for piece %d: %w", pdi.DealInfo.DealID, i, err)}
} }
if proposal.PieceCID != piece.CommP { if proposal.PieceCID != pdi.Piece.PieceCID {
return &ErrInvalidDeals{xerrors.Errorf("piece %d (or %d) of sector %d refers deal %d with wrong CommP: %x != %x", i, len(si.Pieces), si.SectorNumber, piece.DealID, piece.CommP, proposal.PieceCID)} return &ErrInvalidDeals{xerrors.Errorf("piece %d (or %d) of sector %d refers deal %d with wrong PieceCID: %x != %x", i, len(si.PiecesWithOptionalDealInfo), si.SectorNumber, pdi.DealInfo.DealID, pdi.Piece.PieceCID, proposal.PieceCID)}
} }
if piece.Size != proposal.PieceSize.Unpadded() { if pdi.Piece.Size != proposal.PieceSize {
return &ErrInvalidDeals{xerrors.Errorf("piece %d (or %d) of sector %d refers deal %d with different size: %d != %d", i, len(si.Pieces), si.SectorNumber, piece.DealID, piece.Size, proposal.PieceSize)} return &ErrInvalidDeals{xerrors.Errorf("piece %d (or %d) of sector %d refers deal %d with different size: %d != %d", i, len(si.PiecesWithOptionalDealInfo), si.SectorNumber, pdi.DealInfo.DealID, pdi.Piece.Size, proposal.PieceSize)}
} }
if height >= proposal.StartEpoch { if height >= proposal.StartEpoch {
return &ErrExpiredDeals{xerrors.Errorf("piece %d (or %d) of sector %d refers expired deal %d - should start at %d, head %d", i, len(si.Pieces), si.SectorNumber, piece.DealID, proposal.StartEpoch, height)} return &ErrExpiredDeals{xerrors.Errorf("piece %d (or %d) of sector %d refers expired deal %d - should start at %d, head %d", i, len(si.PiecesWithOptionalDealInfo), si.SectorNumber, pdi.DealInfo.DealID, proposal.StartEpoch, height)}
} }
} }
@ -75,7 +73,7 @@ func checkPrecommit(ctx context.Context, maddr address.Address, si SectorInfo, a
return &ErrApi{xerrors.Errorf("getting chain head: %w", err)} return &ErrApi{xerrors.Errorf("getting chain head: %w", err)}
} }
commD, err := api.StateComputeDataCommitment(ctx, maddr, si.SectorType, si.deals(), tok) commD, err := api.StateComputeDataCommitment(ctx, maddr, si.SectorType, si.dealIDs(), tok)
if err != nil { if err != nil {
return &ErrApi{xerrors.Errorf("calling StateComputeDataCommitment: %w", err)} return &ErrApi{xerrors.Errorf("calling StateComputeDataCommitment: %w", err)}
} }

View File

@ -50,19 +50,24 @@ func (evt SectorForceState) applyGlobal(state *SectorInfo) bool {
type SectorStart struct { type SectorStart struct {
ID abi.SectorNumber ID abi.SectorNumber
SectorType abi.RegisteredProof SectorType abi.RegisteredProof
Pieces []Piece Pieces []PieceWithOptionalDealInfo
} }
func (evt SectorStart) apply(state *SectorInfo) { func (evt SectorStart) apply(state *SectorInfo) {
state.SectorNumber = evt.ID state.SectorNumber = evt.ID
state.Pieces = evt.Pieces state.PiecesWithOptionalDealInfo = evt.Pieces
state.SectorType = evt.SectorType state.SectorType = evt.SectorType
} }
type SectorPacked struct{ Pieces []Piece } type SectorPacked struct{ FillerPieces []abi.PieceInfo }
func (evt SectorPacked) apply(state *SectorInfo) { func (evt SectorPacked) apply(state *SectorInfo) {
state.Pieces = append(state.Pieces, evt.Pieces...) for idx := range evt.FillerPieces {
state.PiecesWithOptionalDealInfo = append(state.PiecesWithOptionalDealInfo, PieceWithOptionalDealInfo{
Piece: evt.FillerPieces[idx],
DealInfo: nil, // filler pieces don't have deals associated with them
})
}
} }
type SectorPackingFailed struct{ error } type SectorPackingFailed struct{ error }

View File

@ -16,14 +16,14 @@ func (m *Sealing) pledgeReader(size abi.UnpaddedPieceSize) io.Reader {
return io.LimitReader(&nr.Reader{}, int64(size)) return io.LimitReader(&nr.Reader{}, int64(size))
} }
func (m *Sealing) pledgeSector(ctx context.Context, sectorID abi.SectorID, existingPieceSizes []abi.UnpaddedPieceSize, sizes ...abi.UnpaddedPieceSize) ([]Piece, error) { func (m *Sealing) pledgeSector(ctx context.Context, sectorID abi.SectorID, existingPieceSizes []abi.UnpaddedPieceSize, sizes ...abi.UnpaddedPieceSize) ([]abi.PieceInfo, error) {
if len(sizes) == 0 { if len(sizes) == 0 {
return nil, nil return nil, nil
} }
log.Infof("Pledge %d, contains %+v", sectorID, existingPieceSizes) log.Infof("Pledge %d, contains %+v", sectorID, existingPieceSizes)
out := make([]Piece, len(sizes)) out := make([]abi.PieceInfo, len(sizes))
for i, size := range sizes { for i, size := range sizes {
ppi, err := m.sealer.AddPiece(ctx, sectorID, existingPieceSizes, size, m.pledgeReader(size)) ppi, err := m.sealer.AddPiece(ctx, sectorID, existingPieceSizes, size, m.pledgeReader(size))
if err != nil { if err != nil {
@ -32,9 +32,9 @@ func (m *Sealing) pledgeSector(ctx context.Context, sectorID abi.SectorID, exist
existingPieceSizes = append(existingPieceSizes, size) existingPieceSizes = append(existingPieceSizes, size)
out[i] = Piece{ out[i] = abi.PieceInfo{
Size: ppi.Size.Unpadded(), Size: ppi.Size,
CommP: ppi.PieceCID, PieceCID: ppi.PieceCID,
} }
} }
@ -72,7 +72,15 @@ func (m *Sealing) PledgeSector() error {
return return
} }
if err := m.newSector(sid, rt, pieces); err != nil { pdis := make([]PieceWithOptionalDealInfo, len(pieces))
for idx := range pdis {
pdis[idx] = PieceWithOptionalDealInfo{
Piece: pieces[idx],
DealInfo: nil,
}
}
if err := m.newSector(sid, rt, pdis); err != nil {
log.Errorf("%+v", err) log.Errorf("%+v", err)
return return
} }

View File

@ -11,7 +11,9 @@ import (
func main() { func main() {
err := gen.WriteMapEncodersToFile("./cbor_gen.go", "sealing", err := gen.WriteMapEncodersToFile("./cbor_gen.go", "sealing",
sealing.Piece{}, sealing.PieceWithOptionalDealInfo{},
sealing.DealInfo{},
sealing.DealSchedule{},
sealing.SectorInfo{}, sealing.SectorInfo{},
sealing.Log{}, sealing.Log{},
) )

View File

@ -101,8 +101,8 @@ func (m *Sealing) AllocatePiece(size abi.UnpaddedPieceSize) (sectorID abi.Sector
return sid, 0, nil return sid, 0, nil
} }
func (m *Sealing) SealPiece(ctx context.Context, size abi.UnpaddedPieceSize, r io.Reader, sectorID abi.SectorNumber, dealID abi.DealID) error { func (m *Sealing) SealPiece(ctx context.Context, size abi.UnpaddedPieceSize, r io.Reader, sectorID abi.SectorNumber, pdi PieceWithDealInfo) error {
log.Infof("Seal piece for deal %d", dealID) log.Infof("Seal piece for deal %d", pdi.DealInfo.DealID)
ppi, err := m.sealer.AddPiece(ctx, m.minerSector(sectorID), []abi.UnpaddedPieceSize{}, size, r) ppi, err := m.sealer.AddPiece(ctx, m.minerSector(sectorID), []abi.UnpaddedPieceSize{}, size, r)
if err != nil { if err != nil {
@ -114,17 +114,18 @@ func (m *Sealing) SealPiece(ctx context.Context, size abi.UnpaddedPieceSize, r i
return xerrors.Errorf("bad sector size: %w", err) return xerrors.Errorf("bad sector size: %w", err)
} }
return m.newSector(sectorID, rt, []Piece{ return m.newSector(sectorID, rt, []PieceWithOptionalDealInfo{
{ {
DealID: &dealID, Piece: ppi,
DealInfo: &pdi.DealInfo,
Size: ppi.Size.Unpadded(),
CommP: ppi.PieceCID,
}, },
}) })
} }
func (m *Sealing) newSector(sid abi.SectorNumber, rt abi.RegisteredProof, pieces []Piece) error { // newSector accepts a slice of pieces which will have a deal associated with
// them (in the event of a storage deal) or no deal (in the event of sealing
// garbage data)
func (m *Sealing) newSector(sid abi.SectorNumber, rt abi.RegisteredProof, pieces []PieceWithOptionalDealInfo) error {
log.Infof("Start sealing %d", sid) log.Infof("Start sealing %d", sid)
return m.sectors.Send(uint64(sid), SectorStart{ return m.sectors.Send(uint64(sid), SectorStart{
ID: sid, ID: sid,

View File

@ -19,8 +19,8 @@ func (m *Sealing) handlePacking(ctx statemachine.Context, sector SectorInfo) err
log.Infow("performing filling up rest of the sector...", "sector", sector.SectorNumber) log.Infow("performing filling up rest of the sector...", "sector", sector.SectorNumber)
var allocated abi.UnpaddedPieceSize var allocated abi.UnpaddedPieceSize
for _, piece := range sector.Pieces { for _, piece := range sector.PiecesWithOptionalDealInfo {
allocated += piece.Size allocated += piece.Piece.Size.Unpadded()
} }
ubytes := abi.PaddedPieceSize(m.sealer.SectorSize()).Unpadded() ubytes := abi.PaddedPieceSize(m.sealer.SectorSize()).Unpadded()
@ -38,12 +38,12 @@ func (m *Sealing) handlePacking(ctx statemachine.Context, sector SectorInfo) err
log.Warnf("Creating %d filler pieces for sector %d", len(fillerSizes), sector.SectorNumber) log.Warnf("Creating %d filler pieces for sector %d", len(fillerSizes), sector.SectorNumber)
} }
pieces, err := m.pledgeSector(ctx.Context(), m.minerSector(sector.SectorNumber), sector.existingPieces(), fillerSizes...) fillerPieces, err := m.pledgeSector(ctx.Context(), m.minerSector(sector.SectorNumber), sector.existingPieceSizes(), fillerSizes...)
if err != nil { if err != nil {
return xerrors.Errorf("filling up the sector (%v): %w", fillerSizes, err) return xerrors.Errorf("filling up the sector (%v): %w", fillerSizes, err)
} }
return ctx.Send(SectorPacked{Pieces: pieces}) return ctx.Send(SectorPacked{FillerPieces: fillerPieces})
} }
func (m *Sealing) handlePreCommit1(ctx statemachine.Context, sector SectorInfo) error { func (m *Sealing) handlePreCommit1(ctx statemachine.Context, sector SectorInfo) error {
@ -59,9 +59,9 @@ func (m *Sealing) handlePreCommit1(ctx statemachine.Context, sector SectorInfo)
log.Errorf("handlePreCommit1: api error, not proceeding: %+v", err) log.Errorf("handlePreCommit1: api error, not proceeding: %+v", err)
return nil return nil
case *ErrInvalidDeals: case *ErrInvalidDeals:
return ctx.Send(SectorPackingFailed{xerrors.Errorf("invalid deals in sector: %w", err)}) return ctx.Send(SectorPackingFailed{xerrors.Errorf("invalid dealIDs in sector: %w", err)})
case *ErrExpiredDeals: // Probably not much we can do here, maybe re-pack the sector? case *ErrExpiredDeals: // Probably not much we can do here, maybe re-pack the sector?
return ctx.Send(SectorPackingFailed{xerrors.Errorf("expired deals in sector: %w", err)}) return ctx.Send(SectorPackingFailed{xerrors.Errorf("expired dealIDs in sector: %w", err)})
default: default:
return xerrors.Errorf("checkPieces sanity check error: %w", err) return xerrors.Errorf("checkPieces sanity check error: %w", err)
} }
@ -113,13 +113,13 @@ func (m *Sealing) handlePreCommitting(ctx statemachine.Context, sector SectorInf
} }
params := &miner.SectorPreCommitInfo{ params := &miner.SectorPreCommitInfo{
Expiration: 10000000, // TODO: implement Expiration: 10000000, // TODO: implement expiration
SectorNumber: sector.SectorNumber, SectorNumber: sector.SectorNumber,
RegisteredProof: sector.SectorType, RegisteredProof: sector.SectorType,
SealedCID: *sector.CommR, SealedCID: *sector.CommR,
SealRandEpoch: sector.TicketEpoch, SealRandEpoch: sector.TicketEpoch,
DealIDs: sector.deals(), DealIDs: sector.dealIDs(),
} }
enc := new(bytes.Buffer) enc := new(bytes.Buffer)

View File

@ -11,11 +11,30 @@ import (
"github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/specs-storage/storage"
) )
type Piece struct { // PieceWithOptionalDealInfo is a tuple of piece and deal info
DealID *abi.DealID type PieceWithDealInfo struct {
Piece abi.PieceInfo
DealInfo DealInfo
}
Size abi.UnpaddedPieceSize // PieceWithOptionalDealInfo is a tuple of piece info and optional deal
CommP cid.Cid type PieceWithOptionalDealInfo struct {
Piece abi.PieceInfo
DealInfo *DealInfo // nil for pieces which do not yet appear in self-deals
}
// DealInfo is a tuple of deal identity and its schedule
type DealInfo struct {
DealID abi.DealID
DealSchedule DealSchedule
}
// DealSchedule communicates the time interval of a storage deal. The deal must
// appear in a sealed (proven) sector no later than StartEpoch, otherwise it
// is invalid.
type DealSchedule struct {
StartEpoch abi.ChainEpoch
EndEpoch abi.ChainEpoch
} }
type Log struct { type Log struct {
@ -36,8 +55,7 @@ type SectorInfo struct {
SectorType abi.RegisteredProof SectorType abi.RegisteredProof
// Packing // Packing
PiecesWithOptionalDealInfo []PieceWithOptionalDealInfo
Pieces []Piece
// PreCommit1 // PreCommit1
TicketValue abi.SealRandomness TicketValue abi.SealRandomness
@ -69,31 +87,31 @@ type SectorInfo struct {
} }
func (t *SectorInfo) pieceInfos() []abi.PieceInfo { func (t *SectorInfo) pieceInfos() []abi.PieceInfo {
out := make([]abi.PieceInfo, len(t.Pieces)) out := make([]abi.PieceInfo, len(t.PiecesWithOptionalDealInfo))
for i, piece := range t.Pieces { for i, pdi := range t.PiecesWithOptionalDealInfo {
out[i] = abi.PieceInfo{ out[i] = abi.PieceInfo{
Size: piece.Size.Padded(), Size: pdi.Piece.Size,
PieceCID: piece.CommP, PieceCID: pdi.Piece.PieceCID,
} }
} }
return out return out
} }
func (t *SectorInfo) deals() []abi.DealID { func (t *SectorInfo) dealIDs() []abi.DealID {
out := make([]abi.DealID, 0, len(t.Pieces)) out := make([]abi.DealID, 0, len(t.PiecesWithOptionalDealInfo))
for _, piece := range t.Pieces { for _, pdi := range t.PiecesWithOptionalDealInfo {
if piece.DealID == nil { if pdi.DealInfo == nil {
continue continue
} }
out = append(out, *piece.DealID) out = append(out, pdi.DealInfo.DealID)
} }
return out return out
} }
func (t *SectorInfo) existingPieces() []abi.UnpaddedPieceSize { func (t *SectorInfo) existingPieceSizes() []abi.UnpaddedPieceSize {
out := make([]abi.UnpaddedPieceSize, len(t.Pieces)) out := make([]abi.UnpaddedPieceSize, len(t.PiecesWithOptionalDealInfo))
for i, piece := range t.Pieces { for i, pdi := range t.PiecesWithOptionalDealInfo {
out[i] = piece.Size out[i] = pdi.Piece.Size.Unpadded()
} }
return out return out
} }

View File

@ -14,16 +14,26 @@ import (
func TestSectorInfoSelialization(t *testing.T) { func TestSectorInfoSelialization(t *testing.T) {
d := abi.DealID(1234) d := abi.DealID(1234)
dealInfo := DealInfo{
DealID: d,
DealSchedule: DealSchedule{
StartEpoch: 0,
EndEpoch: 100,
},
}
dummyCid := builtin.AccountActorCodeID dummyCid := builtin.AccountActorCodeID
si := &SectorInfo{ si := &SectorInfo{
State: "stateful", State: "stateful",
SectorNumber: 234, SectorNumber: 234,
Nonce: 345, Nonce: 345,
Pieces: []Piece{{ PiecesWithOptionalDealInfo: []PieceWithOptionalDealInfo{{
DealID: &d, Piece: abi.PieceInfo{
Size: 5, Size: 5,
CommP: dummyCid, PieceCID: dummyCid,
},
DealInfo: &dealInfo,
}}, }},
CommD: &dummyCid, CommD: &dummyCid,
CommR: nil, CommR: nil,
@ -52,7 +62,7 @@ func TestSectorInfoSelialization(t *testing.T) {
assert.Equal(t, si.Nonce, si2.Nonce) assert.Equal(t, si.Nonce, si2.Nonce)
assert.Equal(t, si.SectorNumber, si2.SectorNumber) assert.Equal(t, si.SectorNumber, si2.SectorNumber)
assert.Equal(t, si.Pieces, si2.Pieces) assert.Equal(t, si.PiecesWithOptionalDealInfo, si2.PiecesWithOptionalDealInfo)
assert.Equal(t, si.CommD, si2.CommD) assert.Equal(t, si.CommD, si2.CommD)
assert.Equal(t, si.TicketValue, si2.TicketValue) assert.Equal(t, si.TicketValue, si2.TicketValue)
assert.Equal(t, si.TicketEpoch, si2.TicketEpoch) assert.Equal(t, si.TicketEpoch, si2.TicketEpoch)