remove all lotus types from sealing package in preparation for extraction

events adapter

implement StateWaitMsg and StateComputeDataCommitment

implement StateGetSectorPreCommitOnChainInfo

implement ChainHead and SendMsg

implement remaining methods
This commit is contained in:
laser 2020-04-06 11:07:26 -07:00
parent 3ad16c58d7
commit 650a31b050
22 changed files with 704 additions and 416 deletions

View File

@ -12,8 +12,6 @@ import (
"path/filepath"
"strconv"
"github.com/filecoin-project/lotus/node/modules"
"github.com/docker/go-units"
"github.com/google/uuid"
"github.com/ipfs/go-datastore"
@ -26,6 +24,9 @@ import (
"github.com/filecoin-project/go-address"
cborutil "github.com/filecoin-project/go-cbor-util"
paramfetch "github.com/filecoin-project/go-paramfetch"
sectorstorage "github.com/filecoin-project/sector-storage"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/sector-storage/stores"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/market"
@ -40,13 +41,11 @@ import (
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/genesis"
"github.com/filecoin-project/lotus/miner"
"github.com/filecoin-project/lotus/node/modules"
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/lotus/node/repo"
"github.com/filecoin-project/lotus/storage"
"github.com/filecoin-project/lotus/storage/sealing"
sectorstorage "github.com/filecoin-project/sector-storage"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/sector-storage/stores"
)
var initCmd = &cli.Command{
@ -299,9 +298,11 @@ func migratePreSealMeta(ctx context.Context, api lapi.FullNode, metadata string,
CommD: &commD,
CommR: &commR,
Proof: nil,
Ticket: lapi.SealTicket{},
TicketValue: abi.SealRandomness{},
TicketEpoch: 0,
PreCommitMessage: nil,
Seed: lapi.SealSeed{},
SeedValue: abi.InteractiveSealRandomness{},
SeedEpoch: 0,
CommitMessage: nil,
}

View File

@ -7,14 +7,14 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
"github.com/filecoin-project/go-fil-markets/shared"
sectorstorage "github.com/filecoin-project/sector-storage"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/storage"
"github.com/filecoin-project/sector-storage"
"github.com/filecoin-project/sector-storage/ffiwrapper"
)
type retrievalProviderNode struct {
@ -54,7 +54,7 @@ func (rpn *retrievalProviderNode) UnsealSector(ctx context.Context, sectorID uin
Miner: abi.ActorID(mid),
Number: abi.SectorNumber(sectorID),
}
return rpn.sealer.ReadPieceFromSealedSector(ctx, sid, ffiwrapper.UnpaddedByteIndex(offset), abi.UnpaddedPieceSize(length), si.Ticket.Value, *si.CommD)
return rpn.sealer.ReadPieceFromSealedSector(ctx, sid, ffiwrapper.UnpaddedByteIndex(offset), abi.UnpaddedPieceSize(length), si.TicketValue, *si.CommD)
}
func (rpn *retrievalProviderNode) SavePaymentVoucher(ctx context.Context, paymentChannel address.Address, voucher *paych.SignedVoucher, proof []byte, expectedAmount abi.TokenAmount, tok shared.TipSetToken) (abi.TokenAmount, error) {

View File

@ -12,6 +12,9 @@ import (
"github.com/filecoin-project/go-address"
storagemarket "github.com/filecoin-project/go-fil-markets/storagemarket"
sectorstorage "github.com/filecoin-project/sector-storage"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/sector-storage/stores"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/lotus/api"
@ -21,9 +24,6 @@ import (
"github.com/filecoin-project/lotus/node/impl/common"
"github.com/filecoin-project/lotus/storage"
"github.com/filecoin-project/lotus/storage/sectorblocks"
"github.com/filecoin-project/sector-storage"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/sector-storage/stores"
)
type StorageMinerAPI struct {
@ -97,8 +97,14 @@ func (sm *StorageMinerAPI) SectorsStatus(ctx context.Context, sid abi.SectorNumb
CommR: info.CommR,
Proof: info.Proof,
Deals: deals,
Ticket: info.Ticket,
Seed: info.Seed,
Ticket: api.SealTicket{
Value: info.TicketValue,
Epoch: info.TicketEpoch,
},
Seed: api.SealSeed{
Value: info.SeedValue,
Epoch: info.SeedEpoch,
},
Retries: info.Nonce,
LastErr: info.LastErr,

View File

@ -35,6 +35,9 @@ import (
"github.com/filecoin-project/go-fil-markets/storedcounter"
paramfetch "github.com/filecoin-project/go-paramfetch"
"github.com/filecoin-project/go-statestore"
sectorstorage "github.com/filecoin-project/sector-storage"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/sector-storage/stores"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/crypto"
@ -49,9 +52,6 @@ import (
"github.com/filecoin-project/lotus/node/repo"
"github.com/filecoin-project/lotus/storage"
"github.com/filecoin-project/lotus/storage/sealing"
"github.com/filecoin-project/sector-storage"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/sector-storage/stores"
)
func minerAddrFromDS(ds dtypes.MetadataDS) (address.Address, error) {
@ -281,21 +281,18 @@ func SetupBlockProducer(lc fx.Lifecycle, ds dtypes.MetadataDS, api lapi.FullNode
}
func SealTicketGen(fapi lapi.FullNode) sealing.TicketFn {
return func(ctx context.Context) (*lapi.SealTicket, error) {
return func(ctx context.Context) (abi.SealRandomness, abi.ChainEpoch, error) {
ts, err := fapi.ChainHead(ctx)
if err != nil {
return nil, xerrors.Errorf("getting head ts for SealTicket failed: %w", err)
return nil, 0, xerrors.Errorf("getting head ts for SealTicket failed: %w", err)
}
r, err := fapi.ChainGetRandomness(ctx, ts.Key(), crypto.DomainSeparationTag_SealRandomness, ts.Height()-build.SealRandomnessLookback, nil)
if err != nil {
return nil, xerrors.Errorf("getting randomness for SealTicket failed: %w", err)
return nil, 0, xerrors.Errorf("getting randomness for SealTicket failed: %w", err)
}
return &lapi.SealTicket{
Epoch: ts.Height() - build.SealRandomnessLookback,
Value: abi.SealRandomness(r),
}, nil
return abi.SealRandomness(r), ts.Height() - build.SealRandomnessLookback, nil
}
}

29
storage/adapter_events.go Normal file
View File

@ -0,0 +1,29 @@
package storage
import (
"context"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/lotus/chain/events"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/storage/sealing"
)
var _ sealing.Events = new(EventsAdapter)
type EventsAdapter struct {
delegate events.Events
}
func NewEventsAdapter(api events.Events) EventsAdapter {
return EventsAdapter{delegate: api}
}
func (e EventsAdapter) ChainAt(hnd sealing.HeightHandler, rev sealing.RevertHandler, confidence int, h abi.ChainEpoch) error {
return e.delegate.ChainAt(func(ctx context.Context, ts *types.TipSet, curH abi.ChainEpoch) error {
return hnd(ctx, ts.Key().Bytes(), curH)
}, func(ctx context.Context, ts *types.TipSet) error {
return rev(ctx, ts.Key().Bytes())
}, confidence, h)
}

View File

@ -0,0 +1,176 @@
package storage
import (
"bytes"
"context"
"github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/market"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/lotus/api/apibstore"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/storage/sealing"
)
var _ sealing.SealingAPI = new(SealingAPIAdapter)
type SealingAPIAdapter struct {
delegate storageMinerApi
}
func NewSealingAPIAdapter(api storageMinerApi) SealingAPIAdapter {
return SealingAPIAdapter{delegate: api}
}
func (s SealingAPIAdapter) StateWaitMsg(ctx context.Context, mcid cid.Cid) (sealing.MsgLookup, error) {
wmsg, err := s.delegate.StateWaitMsg(ctx, mcid)
if err != nil {
return sealing.MsgLookup{}, err
}
return sealing.MsgLookup{
Receipt: sealing.MessageReceipt{
ExitCode: wmsg.Receipt.ExitCode,
Return: wmsg.Receipt.Return,
GasUsed: wmsg.Receipt.GasUsed,
},
TipSetTok: wmsg.TipSet.Key().Bytes(),
Height: wmsg.TipSet.Height(),
}, nil
}
func (s SealingAPIAdapter) StateComputeDataCommitment(ctx context.Context, maddr address.Address, sectorType abi.RegisteredProof, deals []abi.DealID, tok sealing.TipSetToken) (cid.Cid, error) {
tsk, err := types.TipSetKeyFromBytes(tok)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err)
}
ccparams, err := actors.SerializeParams(&market.ComputeDataCommitmentParams{
DealIDs: deals,
SectorType: sectorType,
})
if err != nil {
return cid.Undef, xerrors.Errorf("computing params for ComputeDataCommitment: %w", err)
}
ccmt := &types.Message{
To: builtin.StorageMarketActorAddr,
From: maddr,
Value: types.NewInt(0),
GasPrice: types.NewInt(0),
GasLimit: 9999999999,
Method: builtin.MethodsMarket.ComputeDataCommitment,
Params: ccparams,
}
r, err := s.delegate.StateCall(ctx, ccmt, tsk)
if err != nil {
return cid.Undef, xerrors.Errorf("calling ComputeDataCommitment: %w", err)
}
if r.MsgRct.ExitCode != 0 {
return cid.Undef, xerrors.Errorf("receipt for ComputeDataCommitment had exit code %d", r.MsgRct.ExitCode)
}
var c cbg.CborCid
if err := c.UnmarshalCBOR(bytes.NewReader(r.MsgRct.Return)); err != nil {
return cid.Undef, xerrors.Errorf("failed to unmarshal CBOR to CborCid: %w", err)
}
return cid.Cid(c), nil
}
func (s SealingAPIAdapter) StateGetSectorPreCommitOnChainInfo(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok sealing.TipSetToken) (*miner.SectorPreCommitOnChainInfo, error) {
tsk, err := types.TipSetKeyFromBytes(tok)
if err != nil {
return nil, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err)
}
act, err := s.delegate.StateGetActor(ctx, maddr, tsk)
if err != nil {
return nil, xerrors.Errorf("handleSealFailed(%d): temp error: %+v", sectorNumber, err)
}
st, err := s.delegate.ChainReadObj(ctx, act.Head)
if err != nil {
return nil, xerrors.Errorf("handleSealFailed(%d): temp error: %+v", sectorNumber, err)
}
var state miner.State
if err := state.UnmarshalCBOR(bytes.NewReader(st)); err != nil {
return nil, xerrors.Errorf("handleSealFailed(%d): temp error: unmarshaling miner state: %+v", sectorNumber, err)
}
var pci miner.SectorPreCommitOnChainInfo
precommits := adt.AsMap(store.ActorStore(ctx, apibstore.NewAPIBlockstore(s.delegate)), state.PreCommittedSectors)
if _, err := precommits.Get(adt.UIntKey(uint64(sectorNumber)), &pci); err != nil {
return nil, err
}
return &pci, nil
}
func (s SealingAPIAdapter) StateMarketStorageDeal(ctx context.Context, dealID abi.DealID, tok sealing.TipSetToken) (market.DealProposal, market.DealState, error) {
tsk, err := types.TipSetKeyFromBytes(tok)
if err != nil {
return market.DealProposal{}, market.DealState{}, err
}
deal, err := s.delegate.StateMarketStorageDeal(ctx, dealID, tsk)
if err != nil {
return market.DealProposal{}, market.DealState{}, err
}
return deal.Proposal, deal.State, nil
}
func (s SealingAPIAdapter) SendMsg(ctx context.Context, from, to address.Address, method abi.MethodNum, value, gasPrice big.Int, gasLimit int64, params []byte) (cid.Cid, error) {
msg := types.Message{
To: to,
From: from,
Value: value,
GasPrice: gasPrice,
GasLimit: gasLimit,
Method: method,
Params: params,
}
smsg, err := s.delegate.MpoolPushMessage(ctx, &msg)
if err != nil {
return cid.Undef, err
}
return smsg.Cid(), nil
}
func (s SealingAPIAdapter) ChainHead(ctx context.Context) (sealing.TipSetToken, abi.ChainEpoch, error) {
head, err := s.delegate.ChainHead(ctx)
if err != nil {
return nil, 0, err
}
return head.Key().Bytes(), head.Height(), nil
}
func (s SealingAPIAdapter) ChainGetRandomness(ctx context.Context, tok sealing.TipSetToken, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
tsk, err := types.TipSetKeyFromBytes(tok)
if err != nil {
return nil, err
}
return s.delegate.ChainGetRandomness(ctx, tsk, personalization, randEpoch, entropy)
}
func (s SealingAPIAdapter) ChainReadObj(ctx context.Context, ocid cid.Cid) ([]byte, error) {
return s.delegate.ChainReadObj(ctx, ocid)
}

View File

@ -12,13 +12,13 @@ import (
"github.com/libp2p/go-libp2p-core/host"
"golang.org/x/xerrors"
"github.com/filecoin-project/sector-storage"
"github.com/filecoin-project/go-address"
sectorstorage "github.com/filecoin-project/sector-storage"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-storage/storage"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/specs-storage/storage"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
@ -100,7 +100,7 @@ func (m *Miner) Run(ctx context.Context) error {
}
evts := events.NewEvents(ctx, m.api)
m.sealing = sealing.New(m.api, evts, m.maddr, m.worker, m.ds, m.sealer, m.sc, m.verif, m.tktFn)
m.sealing = sealing.New(NewSealingAPIAdapter(m.api), NewEventsAdapter(*evts), m.maddr, m.worker, m.ds, m.sealer, m.sc, m.verif, m.tktFn)
go m.sealing.Run(ctx)

View File

@ -6,7 +6,6 @@ import (
"fmt"
"io"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/specs-actors/actors/abi"
cbg "github.com/whyrusleeping/cbor-gen"
xerrors "golang.org/x/xerrors"
@ -182,7 +181,7 @@ func (t *SectorInfo) MarshalCBOR(w io.Writer) error {
return err
}
// t.State (api.SectorState) (string)
// t.State (uint64) (uint64)
if len("State") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"State\" was too long")
}
@ -194,14 +193,7 @@ func (t *SectorInfo) MarshalCBOR(w io.Writer) error {
return err
}
if len(t.State) > cbg.MaxLength {
return xerrors.Errorf("Value in field t.State was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.State)))); err != nil {
return err
}
if _, err := w.Write([]byte(t.State)); err != nil {
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.State))); err != nil {
return err
}
@ -284,45 +276,6 @@ func (t *SectorInfo) MarshalCBOR(w io.Writer) error {
}
}
// t.Ticket (api.SealTicket) (struct)
if len("Ticket") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"Ticket\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("Ticket")))); err != nil {
return err
}
if _, err := w.Write([]byte("Ticket")); err != nil {
return err
}
if err := t.Ticket.MarshalCBOR(w); err != nil {
return err
}
// t.PreCommit1Out (storage.PreCommit1Out) (slice)
if len("PreCommit1Out") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"PreCommit1Out\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("PreCommit1Out")))); err != nil {
return err
}
if _, err := w.Write([]byte("PreCommit1Out")); err != nil {
return err
}
if len(t.PreCommit1Out) > cbg.ByteArrayMaxLen {
return xerrors.Errorf("Byte array in field t.PreCommit1Out was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.PreCommit1Out)))); err != nil {
return err
}
if _, err := w.Write(t.PreCommit1Out); err != nil {
return err
}
// t.CommD (cid.Cid) (struct)
if len("CommD") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"CommD\" was too long")
@ -390,6 +343,51 @@ func (t *SectorInfo) MarshalCBOR(w io.Writer) error {
return err
}
// t.TicketValue (abi.SealRandomness) (slice)
if len("TicketValue") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"TicketValue\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("TicketValue")))); err != nil {
return err
}
if _, err := w.Write([]byte("TicketValue")); err != nil {
return err
}
if len(t.TicketValue) > cbg.ByteArrayMaxLen {
return xerrors.Errorf("Byte array in field t.TicketValue was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.TicketValue)))); err != nil {
return err
}
if _, err := w.Write(t.TicketValue); err != nil {
return err
}
// t.TicketEpoch (abi.ChainEpoch) (int64)
if len("TicketEpoch") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"TicketEpoch\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("TicketEpoch")))); err != nil {
return err
}
if _, err := w.Write([]byte("TicketEpoch")); err != nil {
return err
}
if t.TicketEpoch >= 0 {
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.TicketEpoch))); err != nil {
return err
}
} else {
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.TicketEpoch)-1)); err != nil {
return err
}
}
// t.PreCommitMessage (cid.Cid) (struct)
if len("PreCommitMessage") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"PreCommitMessage\" was too long")
@ -412,21 +410,50 @@ func (t *SectorInfo) MarshalCBOR(w io.Writer) error {
}
}
// t.Seed (api.SealSeed) (struct)
if len("Seed") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"Seed\" was too long")
// t.SeedValue (abi.InteractiveSealRandomness) (slice)
if len("SeedValue") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"SeedValue\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("Seed")))); err != nil {
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("SeedValue")))); err != nil {
return err
}
if _, err := w.Write([]byte("Seed")); err != nil {
if _, err := w.Write([]byte("SeedValue")); err != nil {
return err
}
if err := t.Seed.MarshalCBOR(w); err != nil {
if len(t.SeedValue) > cbg.ByteArrayMaxLen {
return xerrors.Errorf("Byte array in field t.SeedValue was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.SeedValue)))); err != nil {
return err
}
if _, err := w.Write(t.SeedValue); err != nil {
return err
}
// t.SeedEpoch (abi.ChainEpoch) (int64)
if len("SeedEpoch") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"SeedEpoch\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("SeedEpoch")))); err != nil {
return err
}
if _, err := w.Write([]byte("SeedEpoch")); err != nil {
return err
}
if t.SeedEpoch >= 0 {
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SeedEpoch))); err != nil {
return err
}
} else {
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SeedEpoch)-1)); err != nil {
return err
}
}
// t.CommitMessage (cid.Cid) (struct)
if len("CommitMessage") > cbg.MaxLength {
@ -450,22 +477,6 @@ func (t *SectorInfo) MarshalCBOR(w io.Writer) error {
}
}
// t.InvalidProofs (uint64) (uint64)
if len("InvalidProofs") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"InvalidProofs\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("InvalidProofs")))); err != nil {
return err
}
if _, err := w.Write([]byte("InvalidProofs")); err != nil {
return err
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.InvalidProofs))); err != nil {
return err
}
// t.FaultReportMsg (cid.Cid) (struct)
if len("FaultReportMsg") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"FaultReportMsg\" was too long")
@ -568,16 +579,20 @@ func (t *SectorInfo) UnmarshalCBOR(r io.Reader) error {
}
switch name {
// t.State (api.SectorState) (string)
// t.State (uint64) (uint64)
case "State":
{
sval, err := cbg.ReadString(br)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.State = uint64(extra)
t.State = api.SectorState(sval)
}
// t.SectorID (abi.SectorNumber) (uint64)
case "SectorID":
@ -663,34 +678,6 @@ func (t *SectorInfo) UnmarshalCBOR(r io.Reader) error {
t.Pieces[i] = v
}
// t.Ticket (api.SealTicket) (struct)
case "Ticket":
{
if err := t.Ticket.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.Ticket: %w", err)
}
}
// t.PreCommit1Out (storage.PreCommit1Out) (slice)
case "PreCommit1Out":
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if extra > cbg.ByteArrayMaxLen {
return fmt.Errorf("t.PreCommit1Out: byte array too large (%d)", extra)
}
if maj != cbg.MajByteString {
return fmt.Errorf("expected byte array")
}
t.PreCommit1Out = make([]byte, extra)
if _, err := io.ReadFull(br, t.PreCommit1Out); err != nil {
return err
}
// t.CommD (cid.Cid) (struct)
case "CommD":
@ -759,6 +746,50 @@ func (t *SectorInfo) UnmarshalCBOR(r io.Reader) error {
if _, err := io.ReadFull(br, t.Proof); err != nil {
return err
}
// t.TicketValue (abi.SealRandomness) (slice)
case "TicketValue":
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if extra > cbg.ByteArrayMaxLen {
return fmt.Errorf("t.TicketValue: byte array too large (%d)", extra)
}
if maj != cbg.MajByteString {
return fmt.Errorf("expected byte array")
}
t.TicketValue = make([]byte, extra)
if _, err := io.ReadFull(br, t.TicketValue); err != nil {
return err
}
// t.TicketEpoch (abi.ChainEpoch) (int64)
case "TicketEpoch":
{
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.TicketEpoch = abi.ChainEpoch(extraI)
}
// t.PreCommitMessage (cid.Cid) (struct)
case "PreCommitMessage":
@ -784,15 +815,49 @@ func (t *SectorInfo) UnmarshalCBOR(r io.Reader) error {
}
}
// t.Seed (api.SealSeed) (struct)
case "Seed":
// t.SeedValue (abi.InteractiveSealRandomness) (slice)
case "SeedValue":
{
if err := t.Seed.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.Seed: %w", err)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if extra > cbg.ByteArrayMaxLen {
return fmt.Errorf("t.SeedValue: byte array too large (%d)", extra)
}
if maj != cbg.MajByteString {
return fmt.Errorf("expected byte array")
}
t.SeedValue = make([]byte, extra)
if _, err := io.ReadFull(br, t.SeedValue); err != nil {
return err
}
// t.SeedEpoch (abi.ChainEpoch) (int64)
case "SeedEpoch":
{
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.SeedEpoch = abi.ChainEpoch(extraI)
}
// t.CommitMessage (cid.Cid) (struct)
case "CommitMessage":
@ -818,21 +883,6 @@ func (t *SectorInfo) UnmarshalCBOR(r io.Reader) error {
t.CommitMessage = &c
}
}
// t.InvalidProofs (uint64) (uint64)
case "InvalidProofs":
{
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.InvalidProofs = uint64(extra)
}
// t.FaultReportMsg (cid.Cid) (struct)
case "FaultReportMsg":

View File

@ -1,25 +1,18 @@
package sealing
import (
"bytes"
"context"
"github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/sector-storage/zerocomm"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/market"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/sector-storage/zerocomm"
log "github.com/mgutz/logxi/v1"
)
// TODO: For now we handle this by halting state execution, when we get jsonrpc reconnecting
@ -41,8 +34,8 @@ type ErrInvalidProof struct{ error }
// - Piece commitments match with on chain deals
// - Piece sizes match
// - Deals aren't expired
func checkPieces(ctx context.Context, si SectorInfo, api sealingApi) error {
head, err := api.ChainHead(ctx)
func checkPieces(ctx context.Context, si SectorInfo, api SealingAPI) error {
tok, height, err := api.ChainHead(ctx)
if err != nil {
return &ErrApi{xerrors.Errorf("getting chain head: %w", err)}
}
@ -55,21 +48,21 @@ func checkPieces(ctx context.Context, si SectorInfo, api sealingApi) error {
}
continue
}
deal, err := api.StateMarketStorageDeal(ctx, *piece.DealID, types.EmptyTSK)
proposal, _, err := api.StateMarketStorageDeal(ctx, *piece.DealID, tok)
if err != nil {
return &ErrApi{xerrors.Errorf("getting deal %d for piece %d: %w", piece.DealID, i, err)}
}
if deal.Proposal.PieceCID != piece.CommP {
return &ErrInvalidDeals{xerrors.Errorf("piece %d (or %d) of sector %d refers deal %d with wrong CommP: %x != %x", i, len(si.Pieces), si.SectorID, piece.DealID, piece.CommP, deal.Proposal.PieceCID)}
if proposal.PieceCID != piece.CommP {
return &ErrInvalidDeals{xerrors.Errorf("piece %d (or %d) of sector %d refers deal %d with wrong CommP: %x != %x", i, len(si.Pieces), si.SectorID, piece.DealID, piece.CommP, proposal.PieceCID)}
}
if piece.Size != deal.Proposal.PieceSize.Unpadded() {
return &ErrInvalidDeals{xerrors.Errorf("piece %d (or %d) of sector %d refers deal %d with different size: %d != %d", i, len(si.Pieces), si.SectorID, piece.DealID, piece.Size, deal.Proposal.PieceSize)}
if piece.Size != proposal.PieceSize.Unpadded() {
return &ErrInvalidDeals{xerrors.Errorf("piece %d (or %d) of sector %d refers deal %d with different size: %d != %d", i, len(si.Pieces), si.SectorID, piece.DealID, piece.Size, proposal.PieceSize)}
}
if head.Height() >= deal.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.SectorID, piece.DealID, deal.Proposal.StartEpoch, head.Height())}
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.SectorID, piece.DealID, proposal.StartEpoch, height)}
}
}
@ -78,55 +71,30 @@ func checkPieces(ctx context.Context, si SectorInfo, api sealingApi) error {
// checkPrecommit checks that data commitment generated in the sealing process
// matches pieces, and that the seal ticket isn't expired
func checkPrecommit(ctx context.Context, maddr address.Address, si SectorInfo, api sealingApi) (err error) {
head, err := api.ChainHead(ctx)
func checkPrecommit(ctx context.Context, maddr address.Address, si SectorInfo, api SealingAPI) (err error) {
tok, height, err := api.ChainHead(ctx)
if err != nil {
return &ErrApi{xerrors.Errorf("getting chain head: %w", err)}
}
ccparams, err := actors.SerializeParams(&market.ComputeDataCommitmentParams{
DealIDs: si.deals(),
SectorType: si.SectorType,
})
commD, err := api.StateComputeDataCommitment(ctx, maddr, si.SectorType, si.deals(), tok)
if err != nil {
return xerrors.Errorf("computing params for ComputeDataCommitment: %w", err)
return &ErrApi{xerrors.Errorf("calling StateComputeDataCommitment: %w", err)}
}
ccmt := &types.Message{
To: builtin.StorageMarketActorAddr,
From: maddr,
Value: types.NewInt(0),
GasPrice: types.NewInt(0),
GasLimit: 9999999999,
Method: builtin.MethodsMarket.ComputeDataCommitment,
Params: ccparams,
}
r, err := api.StateCall(ctx, ccmt, types.EmptyTSK)
if err != nil {
return &ErrApi{xerrors.Errorf("calling ComputeDataCommitment: %w", err)}
}
if r.MsgRct.ExitCode != 0 {
return &ErrBadCommD{xerrors.Errorf("receipt for ComputeDataCommitment had exit code %d", r.MsgRct.ExitCode)}
if !commD.Equals(*si.CommD) {
return &ErrBadCommD{xerrors.Errorf("on chain CommD differs from sector: %s != %s", commD, si.CommD)}
}
var c cbg.CborCid
if err := c.UnmarshalCBOR(bytes.NewReader(r.MsgRct.Return)); err != nil {
return err
}
if cid.Cid(c) != *si.CommD {
return &ErrBadCommD{xerrors.Errorf("on chain CommD differs from sector: %s != %s", cid.Cid(c), si.CommD)}
}
if int64(head.Height())-int64(si.Ticket.Epoch+build.SealRandomnessLookback) > build.SealRandomnessLookbackLimit {
return &ErrExpiredTicket{xerrors.Errorf("ticket expired: seal height: %d, head: %d", si.Ticket.Epoch+build.SealRandomnessLookback, head.Height())}
if int64(height)-int64(si.TicketEpoch+SealRandomnessLookback) > SealRandomnessLookbackLimit {
return &ErrExpiredTicket{xerrors.Errorf("ticket expired: seal height: %d, head: %d", si.TicketEpoch+SealRandomnessLookback, height)}
}
return nil
}
func (m *Sealing) checkCommit(ctx context.Context, si SectorInfo, proof []byte) (err error) {
head, err := m.api.ChainHead(ctx)
tok, height, err := m.api.ChainHead(ctx)
if err != nil {
return &ErrApi{xerrors.Errorf("getting chain head: %w", err)}
}

View File

@ -0,0 +1,13 @@
package sealing
// Epochs
const Finality = 500
// Epochs
const SealRandomnessLookback = Finality
// Epochs
const SealRandomnessLookbackLimit = SealRandomnessLookback + 2000
// Epochs
const InteractivePoRepConfidence = 6

15
storage/sealing/events.go Normal file
View File

@ -0,0 +1,15 @@
package sealing
import (
"context"
"github.com/filecoin-project/specs-actors/actors/abi"
)
// `curH`-`ts.Height` = `confidence`
type HeightHandler func(ctx context.Context, tok TipSetToken, curH abi.ChainEpoch) error
type RevertHandler func(ctx context.Context, tok TipSetToken) error
type Events interface {
ChainAt(hnd HeightHandler, rev RevertHandler, confidence int, h abi.ChainEpoch) error
}

View File

@ -1,6 +1,7 @@
package sealing
import (
"bytes"
"context"
"encoding/json"
"fmt"
@ -9,10 +10,10 @@ import (
"golang.org/x/xerrors"
"github.com/filecoin-project/go-statemachine"
"github.com/filecoin-project/specs-actors/actors/abi"
statemachine "github.com/filecoin-project/go-statemachine"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/prometheus/common/log"
)
func (m *Sealing) Plan(events []statemachine.Event, user interface{}) (interface{}, uint64, error) {
@ -54,19 +55,19 @@ var fsmPlanners = map[api.SectorState]func(events []statemachine.Event, state *S
on(SectorSeedReady{}, api.Committing),
on(SectorChainPreCommitFailed{}, api.PreCommitFailed),
),
api.Committing: planCommitting,
api.CommitWait: planOne(
on(SectorProving{}, api.FinalizeSector),
on(SectorCommitFailed{}, api.CommitFailed),
Committing: planCommitting,
CommitWait: planOne(
on(SectorProving{}, FinalizeSector),
on(SectorCommitFailed{}, CommitFailed),
),
api.FinalizeSector: planOne(
on(SectorFinalized{}, api.Proving),
FinalizeSector: planOne(
on(SectorFinalized{}, Proving),
),
api.Proving: planOne(
on(SectorFaultReported{}, api.FaultReported),
on(SectorFaulty{}, api.Faulty),
Proving: planOne(
on(SectorFaultReported{}, FaultReported),
on(SectorFaulty{}, Faulty),
),
api.SealFailed: planOne(
@ -87,10 +88,10 @@ var fsmPlanners = map[api.SectorState]func(events []statemachine.Event, state *S
on(SectorRetryInvalidProof{}, api.Committing),
),
api.Faulty: planOne(
on(SectorFaultReported{}, api.FaultReported),
Faulty: planOne(
on(SectorFaultReported{}, FaultReported),
),
api.FaultedFinal: final,
FaultedFinal: final,
}
func (m *Sealing) plan(events []statemachine.Event, state *SectorInfo) (func(statemachine.Context, SectorInfo) error, error) {
@ -170,7 +171,7 @@ func (m *Sealing) plan(events []statemachine.Event, state *SectorInfo) (func(sta
switch state.State {
// Happy path
case api.Packing:
case Packing:
return m.handlePacking, nil
case api.PreCommit1:
return m.handlePreCommit1, nil
@ -178,22 +179,22 @@ func (m *Sealing) plan(events []statemachine.Event, state *SectorInfo) (func(sta
return m.handlePreCommit2, nil
case api.PreCommitting:
return m.handlePreCommitting, nil
case api.WaitSeed:
case WaitSeed:
return m.handleWaitSeed, nil
case api.Committing:
case Committing:
return m.handleCommitting, nil
case api.CommitWait:
case CommitWait:
return m.handleCommitWait, nil
case api.FinalizeSector:
case FinalizeSector:
return m.handleFinalizeSector, nil
case api.Proving:
case Proving:
// TODO: track sector health / expiration
log.Infof("Proving sector %d", state.SectorID)
// Handled failure modes
case api.SealFailed:
case SealFailed:
return m.handleSealFailed, nil
case api.PreCommitFailed:
case PreCommitFailed:
return m.handlePreCommitFailed, nil
case api.ComputeProofFailed:
return m.handleComputeProofFailed, nil
@ -201,15 +202,15 @@ func (m *Sealing) plan(events []statemachine.Event, state *SectorInfo) (func(sta
return m.handleCommitFailed, nil
// Faults
case api.Faulty:
case Faulty:
return m.handleFaulty, nil
case api.FaultReported:
case FaultReported:
return m.handleFaultReported, nil
// Fatal errors
case api.UndefinedSectorState:
case UndefinedSectorState:
log.Error("sector update with undefined state!")
case api.FailedUnrecoverable:
case FailedUnrecoverable:
log.Errorf("sector %d failed unrecoverably", state.SectorID)
default:
log.Errorf("unexpected sector update state: %d", state.State)
@ -227,22 +228,22 @@ func planCommitting(events []statemachine.Event, state *SectorInfo) error {
}
case SectorCommitted: // the normal case
e.apply(state)
state.State = api.CommitWait
state.State = CommitWait
case SectorSeedReady: // seed changed :/
if e.Seed.Equals(&state.Seed) {
if e.SeedEpoch == state.SeedEpoch && bytes.Equal(e.SeedValue, state.SeedValue) {
log.Warnf("planCommitting: got SectorSeedReady, but the seed didn't change")
continue // or it didn't!
}
log.Warnf("planCommitting: commit Seed changed")
e.apply(state)
state.State = api.Committing
state.State = Committing
return nil
case SectorComputeProofFailed:
state.State = api.ComputeProofFailed
case SectorSealPreCommitFailed:
state.State = api.CommitFailed
case SectorCommitFailed:
state.State = api.CommitFailed
state.State = CommitFailed
default:
return xerrors.Errorf("planCommitting got event of unknown type %T, events: %+v", event.User, events)
}
@ -267,7 +268,7 @@ func (m *Sealing) restartSectors(ctx context.Context) error {
return nil
}
func (m *Sealing) ForceSectorState(ctx context.Context, id abi.SectorNumber, state api.SectorState) error {
func (m *Sealing) ForceSectorState(ctx context.Context, id abi.SectorNumber, state SectorState) error {
return m.sectors.Send(id, SectorForceState{state})
}
@ -275,13 +276,13 @@ func final(events []statemachine.Event, state *SectorInfo) error {
return xerrors.Errorf("didn't expect any events in state %s, got %+v", state.State, events)
}
func on(mut mutator, next api.SectorState) func() (mutator, api.SectorState) {
return func() (mutator, api.SectorState) {
func on(mut mutator, next SectorState) func() (mutator, SectorState) {
return func() (mutator, SectorState) {
return mut, next
}
}
func planOne(ts ...func() (mut mutator, next api.SectorState)) func(events []statemachine.Event, state *SectorInfo) error {
func planOne(ts ...func() (mut mutator, next SectorState)) func(events []statemachine.Event, state *SectorInfo) error {
return func(events []statemachine.Event, state *SectorInfo) error {
if len(events) != 1 {
for _, event := range events {

View File

@ -4,9 +4,10 @@ import (
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-storage/storage"
"github.com/ipfs/go-cid"
"github.com/prometheus/common/log"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/specs-actors/actors/abi"
)
type mutator interface {
@ -39,7 +40,7 @@ func (evt SectorFatalError) applyGlobal(state *SectorInfo) bool {
}
type SectorForceState struct {
State api.SectorState
State SectorState
}
func (evt SectorForceState) applyGlobal(state *SectorInfo) bool {
@ -73,12 +74,14 @@ func (evt SectorPackingFailed) apply(*SectorInfo) {}
type SectorPreCommit1 struct {
PreCommit1Out storage.PreCommit1Out
Ticket api.SealTicket
TicketValue abi.SealRandomness
TicketEpoch abi.ChainEpoch
}
func (evt SectorPreCommit1) apply(state *SectorInfo) {
state.PreCommit1Out = evt.PreCommit1Out
state.Ticket = evt.Ticket
state.TicketEpoch = evt.TicketEpoch
state.TicketValue = evt.TicketValue
}
type SectorPreCommit2 struct {
@ -114,11 +117,13 @@ func (evt SectorPreCommitted) apply(state *SectorInfo) {
}
type SectorSeedReady struct {
Seed api.SealSeed
SeedValue abi.InteractiveSealRandomness
SeedEpoch abi.ChainEpoch
}
func (evt SectorSeedReady) apply(state *SectorInfo) {
state.Seed = evt.Seed
state.SeedEpoch = evt.SeedEpoch
state.SeedValue = evt.SeedValue
}
type SectorComputeProofFailed struct{ error }

View File

@ -7,7 +7,6 @@ import (
"github.com/stretchr/testify/require"
"github.com/filecoin-project/go-statemachine"
"github.com/filecoin-project/lotus/api"
)
@ -32,7 +31,7 @@ func TestHappyPath(t *testing.T) {
m := test{
s: &Sealing{},
t: t,
state: &SectorInfo{State: api.Packing},
state: &SectorInfo{State: Packing},
}
m.planSingle(SectorPacked{})
@ -45,26 +44,26 @@ func TestHappyPath(t *testing.T) {
require.Equal(m.t, m.state.State, api.PreCommitting)
m.planSingle(SectorPreCommitted{})
require.Equal(m.t, m.state.State, api.WaitSeed)
require.Equal(m.t, m.state.State, WaitSeed)
m.planSingle(SectorSeedReady{})
require.Equal(m.t, m.state.State, api.Committing)
require.Equal(m.t, m.state.State, Committing)
m.planSingle(SectorCommitted{})
require.Equal(m.t, m.state.State, api.CommitWait)
require.Equal(m.t, m.state.State, CommitWait)
m.planSingle(SectorProving{})
require.Equal(m.t, m.state.State, api.FinalizeSector)
require.Equal(m.t, m.state.State, FinalizeSector)
m.planSingle(SectorFinalized{})
require.Equal(m.t, m.state.State, api.Proving)
require.Equal(m.t, m.state.State, Proving)
}
func TestSeedRevert(t *testing.T) {
m := test{
s: &Sealing{},
t: t,
state: &SectorInfo{State: api.Packing},
state: &SectorInfo{State: Packing},
}
m.planSingle(SectorPacked{})
@ -77,31 +76,31 @@ func TestSeedRevert(t *testing.T) {
require.Equal(m.t, m.state.State, api.PreCommitting)
m.planSingle(SectorPreCommitted{})
require.Equal(m.t, m.state.State, api.WaitSeed)
require.Equal(m.t, m.state.State, WaitSeed)
m.planSingle(SectorSeedReady{})
require.Equal(m.t, m.state.State, api.Committing)
require.Equal(m.t, m.state.State, Committing)
_, err := m.s.plan([]statemachine.Event{{SectorSeedReady{Seed: api.SealSeed{Epoch: 5}}}, {SectorCommitted{}}}, m.state)
_, err := m.s.plan([]statemachine.Event{{SectorSeedReady{Seed: SealSeed{Epoch: 5}}}, {SectorCommitted{}}}, m.state)
require.NoError(t, err)
require.Equal(m.t, m.state.State, api.Committing)
require.Equal(m.t, m.state.State, Committing)
// not changing the seed this time
_, err = m.s.plan([]statemachine.Event{{SectorSeedReady{Seed: api.SealSeed{Epoch: 5}}}, {SectorCommitted{}}}, m.state)
require.Equal(m.t, m.state.State, api.CommitWait)
_, err = m.s.plan([]statemachine.Event{{SectorSeedReady{Seed: SealSeed{Epoch: 5}}}, {SectorCommitted{}}}, m.state)
require.Equal(m.t, m.state.State, CommitWait)
m.planSingle(SectorProving{})
require.Equal(m.t, m.state.State, api.FinalizeSector)
require.Equal(m.t, m.state.State, FinalizeSector)
m.planSingle(SectorFinalized{})
require.Equal(m.t, m.state.State, api.Proving)
require.Equal(m.t, m.state.State, Proving)
}
func TestPlanCommittingHandlesSectorCommitFailed(t *testing.T) {
m := test{
s: &Sealing{},
t: t,
state: &SectorInfo{State: api.Committing},
state: &SectorInfo{State: Committing},
}
events := []statemachine.Event{{SectorCommitFailed{}}}

View File

@ -2,11 +2,11 @@ package sealing
import (
"context"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"io"
"golang.org/x/xerrors"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/lotus/lib/nullreader"

View File

@ -1,72 +1,76 @@
package sealing
import (
"bytes"
"context"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"io"
"github.com/filecoin-project/go-address"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/namespace"
logging "github.com/ipfs/go-log/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-padreader"
"github.com/filecoin-project/go-statemachine"
"github.com/filecoin-project/go-address"
padreader "github.com/filecoin-project/go-padreader"
statemachine "github.com/filecoin-project/go-statemachine"
sectorstorage "github.com/filecoin-project/sector-storage"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin/market"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/events"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/sector-storage"
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
)
const SectorStorePrefix = "/sectors"
var log = logging.Logger("sectors")
type TicketFn func(context.Context) (*api.SealTicket, error)
type TicketFn func(context.Context) (abi.SealRandomness, abi.ChainEpoch, error)
type SectorIDCounter interface {
Next() (abi.SectorNumber, error)
}
type sealingApi interface { // TODO: trim down
// Call a read only method on actors (no interaction with the chain required)
StateCall(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error)
StateMinerWorker(context.Context, address.Address, types.TipSetKey) (address.Address, error)
StateMinerPostState(ctx context.Context, actor address.Address, ts types.TipSetKey) (*miner.PoStState, error)
StateMinerSectors(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error)
StateMinerProvingSet(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error)
StateMinerSectorSize(context.Context, address.Address, types.TipSetKey) (abi.SectorSize, error)
StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error)
StateWaitMsg(context.Context, cid.Cid) (*api.MsgLookup, error) // TODO: removeme eventually
StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error)
StateMarketStorageDeal(context.Context, abi.DealID, types.TipSetKey) (*api.MarketDeal, error)
type TipSetToken []byte
MpoolPushMessage(context.Context, *types.Message) (*types.SignedMessage, error)
type MsgLookup struct {
Receipt MessageReceipt
TipSetTok TipSetToken
Height abi.ChainEpoch
}
ChainHead(context.Context) (*types.TipSet, error)
ChainNotify(context.Context) (<-chan []*store.HeadChange, error)
ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error)
type MessageReceipt struct {
ExitCode exitcode.ExitCode
Return []byte
GasUsed int64
}
func (mr *MessageReceipt) Equals(o *MessageReceipt) bool {
return mr.ExitCode == o.ExitCode && bytes.Equal(mr.Return, o.Return) && mr.GasUsed == o.GasUsed
}
type MarketDeal struct {
Proposal market.DealProposal
State market.DealState
}
type SealingAPI interface {
StateWaitMsg(context.Context, cid.Cid) (MsgLookup, error)
StateComputeDataCommitment(ctx context.Context, maddr address.Address, sectorType abi.RegisteredProof, deals []abi.DealID, tok TipSetToken) (cid.Cid, error)
StateGetSectorPreCommitOnChainInfo(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok TipSetToken) (*miner.SectorPreCommitOnChainInfo, error)
StateMarketStorageDeal(context.Context, abi.DealID, TipSetToken) (market.DealProposal, market.DealState, error)
SendMsg(ctx context.Context, from, to address.Address, method abi.MethodNum, value, gasPrice big.Int, gasLimit int64, params []byte) (cid.Cid, error)
ChainHead(ctx context.Context) (TipSetToken, abi.ChainEpoch, error)
ChainGetRandomness(ctx context.Context, tok TipSetToken, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
ChainHasObj(context.Context, cid.Cid) (bool, error)
WalletSign(context.Context, address.Address, []byte) (*crypto.Signature, error)
WalletBalance(context.Context, address.Address) (types.BigInt, error)
WalletHas(context.Context, address.Address) (bool, error)
}
type Sealing struct {
api sealingApi
events *events.Events
api SealingAPI
events Events
maddr address.Address
worker address.Address
@ -78,7 +82,7 @@ type Sealing struct {
tktFn TicketFn
}
func New(api sealingApi, events *events.Events, maddr address.Address, worker address.Address, ds datastore.Batching, sealer sectorstorage.SectorManager, sc SectorIDCounter, verif ffiwrapper.Verifier, tktFn TicketFn) *Sealing {
func New(api SealingAPI, events Events, maddr address.Address, worker address.Address, ds datastore.Batching, sealer sectorstorage.SectorManager, sc SectorIDCounter, verif ffiwrapper.Verifier, tktFn TicketFn) *Sealing {
s := &Sealing{
api: api,
events: events,

View File

@ -0,0 +1,74 @@
package sealing
// alias because cbor-gen doesn't like non-alias types
type SectorState = uint64
const (
UndefinedSectorState SectorState = iota
// happy path
Empty
Packing // sector not in sealStore, and not on chain
Unsealed // sealing / queued
PreCommitting // on chain pre-commit
WaitSeed // waiting for seed
Committing
CommitWait // waiting for message to land on chain
FinalizeSector
Proving
_ // reserved
_
_
// recovery handling
// Reseal
_
_
_
_
_
_
_
// error modes
FailedUnrecoverable
SealFailed
PreCommitFailed
SealCommitFailed
CommitFailed
PackingFailed
_
_
_
Faulty // sector is corrupted or gone for some reason
FaultReported // sector has been declared as a fault on chain
FaultedFinal // fault declared on chain
)
var SectorStates = []string{
UndefinedSectorState: "UndefinedSectorState",
Empty: "Empty",
Packing: "Packing",
Unsealed: "Unsealed",
PreCommitting: "PreCommitting",
WaitSeed: "WaitSeed",
Committing: "Committing",
CommitWait: "CommitWait",
FinalizeSector: "FinalizeSector",
Proving: "Proving",
SealFailed: "SealFailed",
PreCommitFailed: "PreCommitFailed",
SealCommitFailed: "SealCommitFailed",
CommitFailed: "CommitFailed",
PackingFailed: "PackingFailed",
FailedUnrecoverable: "FailedUnrecoverable",
Faulty: "Faulty",
FaultReported: "FaultReported",
FaultedFinal: "FaultedFinal",
}

View File

@ -1,21 +1,19 @@
package sealing
import (
"bytes"
"context"
"github.com/filecoin-project/specs-storage/storage"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/go-statemachine"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api"
statemachine "github.com/filecoin-project/go-statemachine"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/specs-storage/storage"
)
func (m *Sealing) handlePacking(ctx statemachine.Context, sector SectorInfo) error {
@ -65,19 +63,20 @@ func (m *Sealing) handlePreCommit1(ctx statemachine.Context, sector SectorInfo)
}
log.Infow("performing sector replication...", "sector", sector.SectorID)
ticket, err := m.tktFn(ctx.Context())
ticketValue, ticketEpoch, err := m.tktFn(ctx.Context())
if err != nil {
return ctx.Send(SectorSealPreCommitFailed{xerrors.Errorf("getting ticket failed: %w", err)})
}
pc1o, err := m.sealer.SealPreCommit1(ctx.Context(), m.minerSector(sector.SectorID), ticket.Value, sector.pieceInfos())
pc1o, err := m.sealer.SealPreCommit1(ctx.Context(), m.minerSector(sector.SectorID), ticketValue, sector.pieceInfos())
if err != nil {
return ctx.Send(SectorSealPreCommitFailed{xerrors.Errorf("seal pre commit(1) failed: %w", err)})
}
return ctx.Send(SectorPreCommit1{
PreCommit1Out: pc1o,
Ticket: *ticket,
TicketValue: ticketValue,
TicketEpoch: ticketEpoch,
})
}
@ -94,7 +93,7 @@ func (m *Sealing) handlePreCommit2(ctx statemachine.Context, sector SectorInfo)
}
func (m *Sealing) handlePreCommitting(ctx statemachine.Context, sector SectorInfo) error {
if err := checkPrecommit(ctx.Context(), m.maddr, sector, m.api); err != nil {
if err := checkPrecommit(ctx.Context(), m.Address(), sector, m.api); err != nil {
switch err.(type) {
case *ErrApi:
log.Errorf("handlePreCommitting: api error, not proceeding: %+v", err)
@ -114,31 +113,22 @@ func (m *Sealing) handlePreCommitting(ctx statemachine.Context, sector SectorInf
RegisteredProof: sector.SectorType,
SealedCID: *sector.CommR,
SealRandEpoch: sector.Ticket.Epoch,
SealRandEpoch: sector.TicketEpoch,
DealIDs: sector.deals(),
}
enc, aerr := actors.SerializeParams(params)
if aerr != nil {
return ctx.Send(SectorChainPreCommitFailed{xerrors.Errorf("could not serialize commit sector parameters: %w", aerr)})
}
msg := &types.Message{
To: m.maddr,
From: m.worker,
Method: builtin.MethodsMiner.PreCommitSector,
Params: enc,
Value: types.NewInt(0), // TODO: need to ensure sufficient collateral
GasLimit: 1000000, /* i dont know help */
GasPrice: types.NewInt(1),
enc := new(bytes.Buffer)
if err := params.MarshalCBOR(enc); err != nil {
return ctx.Send(SectorChainPreCommitFailed{xerrors.Errorf("could not serialize pre-commit sector parameters: %w", err)})
}
log.Info("submitting precommit for sector: ", sector.SectorID)
smsg, err := m.api.MpoolPushMessage(ctx.Context(), msg)
mcid, err := m.api.SendMsg(ctx.Context(), m.worker, m.maddr, builtin.MethodsMiner.PreCommitSector, big.NewInt(0), big.NewInt(1), 1000000, enc.Bytes())
if err != nil {
return ctx.Send(SectorChainPreCommitFailed{xerrors.Errorf("pushing message to mpool: %w", err)})
}
return ctx.Send(SectorPreCommitted{Message: smsg.Cid()})
return ctx.Send(SectorPreCommitted{Message: mcid})
}
func (m *Sealing) handleWaitSeed(ctx statemachine.Context, sector SectorInfo) error {
@ -162,10 +152,9 @@ func (m *Sealing) handleWaitSeed(ctx statemachine.Context, sector SectorInfo) er
}
randHeight := pci.PreCommitEpoch + miner.PreCommitChallengeDelay
log.Infof("precommit for sector %d made it on chain, will start proof computation at height %d", sector.SectorID, randHeight)
err = m.events.ChainAt(func(ectx context.Context, ts *types.TipSet, curH abi.ChainEpoch) error {
rand, err := m.api.ChainGetRandomness(ectx, ts.Key(), crypto.DomainSeparationTag_InteractiveSealChallengeSeed, randHeight, nil)
err = m.events.ChainAt(func(ectx context.Context, tok TipSetToken, curH abi.ChainEpoch) error {
rand, err := m.api.ChainGetRandomness(ectx, tok, crypto.DomainSeparationTag_InteractiveSealChallengeSeed, randHeight, nil)
if err != nil {
err = xerrors.Errorf("failed to get randomness for computing seal proof: %w", err)
@ -173,13 +162,10 @@ func (m *Sealing) handleWaitSeed(ctx statemachine.Context, sector SectorInfo) er
return err
}
ctx.Send(SectorSeedReady{Seed: api.SealSeed{
Epoch: randHeight,
Value: abi.InteractiveSealRandomness(rand),
}})
ctx.Send(SectorSeedReady{SeedValue: abi.InteractiveSealRandomness(rand), SeedEpoch: randHeight})
return nil
}, func(ctx context.Context, ts *types.TipSet) error {
}, func(ctx context.Context, ts TipSetToken) error {
log.Warn("revert in interactive commit sector step")
// TODO: need to cancel running process and restart...
return nil
@ -194,13 +180,13 @@ func (m *Sealing) handleWaitSeed(ctx statemachine.Context, sector SectorInfo) er
func (m *Sealing) handleCommitting(ctx statemachine.Context, sector SectorInfo) error {
log.Info("scheduling seal proof computation...")
log.Infof("KOMIT %d %x(%d); %x(%d); %v; r:%x; d:%x", sector.SectorID, sector.Ticket.Value, sector.Ticket.Epoch, sector.Seed.Value, sector.Seed.Epoch, sector.pieceInfos(), sector.CommR, sector.CommD)
log.Infof("KOMIT %d %x(%d); %x(%d); %v; r:%x; d:%x", sector.SectorID, sector.TicketValue, sector.TicketEpoch, sector.SeedValue, sector.SeedEpoch, sector.pieceInfos(), sector.CommR, sector.CommD)
cids := storage.SectorCids{
Unsealed: *sector.CommD,
Sealed: *sector.CommR,
}
c2in, err := m.sealer.SealCommit1(ctx.Context(), m.minerSector(sector.SectorID), sector.Ticket.Value, sector.Seed.Value, sector.pieceInfos(), cids)
c2in, err := m.sealer.SealCommit1(ctx.Context(), m.minerSector(sector.SectorID), sector.TicketValue, sector.SeedValue, sector.pieceInfos(), cids)
if err != nil {
return ctx.Send(SectorComputeProofFailed{xerrors.Errorf("computing seal proof failed: %w", err)})
}
@ -221,31 +207,20 @@ func (m *Sealing) handleCommitting(ctx statemachine.Context, sector SectorInfo)
Proof: proof,
}
enc, aerr := actors.SerializeParams(params)
if aerr != nil {
return ctx.Send(SectorCommitFailed{xerrors.Errorf("could not serialize commit sector parameters: %w", aerr)})
}
msg := &types.Message{
To: m.maddr,
From: m.worker,
Method: builtin.MethodsMiner.ProveCommitSector,
Params: enc,
Value: types.NewInt(0), // TODO: need to ensure sufficient collateral
GasLimit: 1000000, /* i dont know help */
GasPrice: types.NewInt(1),
enc := new(bytes.Buffer)
if err := params.MarshalCBOR(enc); err != nil {
return ctx.Send(SectorCommitFailed{xerrors.Errorf("could not serialize commit sector parameters: %w", err)})
}
// TODO: check seed / ticket are up to date
smsg, err := m.api.MpoolPushMessage(ctx.Context(), msg)
mcid, err := m.api.SendMsg(ctx.Context(), m.worker, m.maddr, builtin.MethodsMiner.ProveCommitSector, big.NewInt(0), big.NewInt(1), 1000000, enc.Bytes())
if err != nil {
return ctx.Send(SectorCommitFailed{xerrors.Errorf("pushing message to mpool: %w", err)})
}
return ctx.Send(SectorCommitted{
Proof: proof,
Message: smsg.Cid(),
Message: mcid,
})
}
@ -261,7 +236,7 @@ func (m *Sealing) handleCommitWait(ctx statemachine.Context, sector SectorInfo)
}
if mw.Receipt.ExitCode != 0 {
return ctx.Send(SectorCommitFailed{xerrors.Errorf("submitting sector proof failed (exit=%d, msg=%s) (t:%x; s:%x(%d); p:%x)", mw.Receipt.ExitCode, sector.CommitMessage, sector.Ticket.Value, sector.Seed.Value, sector.Seed.Epoch, sector.Proof)})
return ctx.Send(SectorCommitFailed{xerrors.Errorf("submitting sector proof failed (exit=%d, msg=%s) (t:%x; s:%x(%d); p:%x)", mw.Receipt.ExitCode, sector.CommitMessage, sector.TicketValue, sector.SeedValue, sector.SeedEpoch, sector.Proof)})
}
return ctx.Send(SectorProving{})
@ -284,30 +259,22 @@ func (m *Sealing) handleFaulty(ctx statemachine.Context, sector SectorInfo) erro
bf := abi.NewBitField()
bf.Set(uint64(sector.SectorID))
enc, aerr := actors.SerializeParams(&miner.DeclareTemporaryFaultsParams{
params := &miner.DeclareTemporaryFaultsParams{
SectorNumbers: bf,
Duration: 99999999, // TODO: This is very unlikely to be the correct number
})
if aerr != nil {
return xerrors.Errorf("failed to serialize declare fault params: %w", aerr)
}
msg := &types.Message{
To: m.maddr,
From: m.worker,
Method: builtin.MethodsMiner.DeclareTemporaryFaults,
Params: enc,
Value: types.NewInt(0), // TODO: need to ensure sufficient collateral
GasLimit: 1000000, /* i dont know help */
GasPrice: types.NewInt(1),
enc := new(bytes.Buffer)
if err := params.MarshalCBOR(enc); err != nil {
return ctx.Send(SectorCommitFailed{xerrors.Errorf("failed to serialize declare fault params: %w", err)})
}
smsg, err := m.api.MpoolPushMessage(ctx.Context(), msg)
mcid, err := m.api.SendMsg(ctx.Context(), m.worker, m.maddr, builtin.MethodsMiner.DeclareTemporaryFaults, big.NewInt(0), big.NewInt(1), 1000000, enc.Bytes())
if err != nil {
return xerrors.Errorf("failed to push declare faults message to network: %w", err)
}
return ctx.Send(SectorFaultReported{reportMsg: smsg.Cid()})
return ctx.Send(SectorFaultReported{reportMsg: mcid})
}
func (m *Sealing) handleFaultReported(ctx statemachine.Context, sector SectorInfo) error {

View File

@ -1,17 +1,12 @@
package sealing
import (
"bytes"
"time"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-statemachine"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/util/adt"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api/apibstore"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
)
const minRetryTime = 1 * time.Minute
@ -33,36 +28,22 @@ func failedCooldown(ctx statemachine.Context, sector SectorInfo) error {
}
func (m *Sealing) checkPreCommitted(ctx statemachine.Context, sector SectorInfo) (*miner.SectorPreCommitOnChainInfo, bool) {
act, err := m.api.StateGetActor(ctx.Context(), m.maddr, types.EmptyTSK)
tok, _, err := m.api.ChainHead(ctx.Context())
if err != nil {
log.Errorf("handleSealFailed(%d): temp error: %+v", sector.SectorID, err)
return nil, true
}
st, err := m.api.ChainReadObj(ctx.Context(), act.Head)
info, err := m.api.StateGetSectorPreCommitOnChainInfo(ctx.Context(), m.maddr, sector.SectorID, tok)
if err != nil {
log.Errorf("handleSealFailed(%d): temp error: %+v", sector.SectorID, err)
return nil, true
}
var state miner.State
if err := state.UnmarshalCBOR(bytes.NewReader(st)); err != nil {
log.Errorf("handleSealFailed(%d): temp error: unmarshaling miner state: %+v", sector.SectorID, err)
return nil, true
}
var pci miner.SectorPreCommitOnChainInfo
precommits := adt.AsMap(store.ActorStore(ctx.Context(), apibstore.NewAPIBlockstore(m.api)), state.PreCommittedSectors)
if _, err := precommits.Get(adt.UIntKey(uint64(sector.SectorID)), &pci); err != nil {
log.Error(err)
return nil, true
}
return &pci, false
return info, false
}
func (m *Sealing) handleSealFailed(ctx statemachine.Context, sector SectorInfo) error {
if _, is := m.checkPreCommitted(ctx, sector); is {
// TODO: Remove this after we can re-precommit
return nil // noop, for now
@ -76,7 +57,7 @@ func (m *Sealing) handleSealFailed(ctx statemachine.Context, sector SectorInfo)
}
func (m *Sealing) handlePreCommitFailed(ctx statemachine.Context, sector SectorInfo) error {
if err := checkPrecommit(ctx.Context(), m.maddr, sector, m.api); err != nil {
if err := checkPrecommit(ctx.Context(), m.Address(), sector, m.api); err != nil {
switch err.(type) {
case *ErrApi:
log.Errorf("handlePreCommitFailed: api error, not proceeding: %+v", err)

View File

@ -5,7 +5,7 @@ import (
"github.com/filecoin-project/specs-storage/storage"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/specs-actors/actors/abi"
)
type Piece struct {
@ -26,8 +26,8 @@ type Log struct {
}
type SectorInfo struct {
State api.SectorState
SectorID abi.SectorNumber
State SectorState
SectorID abi.SectorNumber // TODO: this field's name should be changed to SectorNumber
Nonce uint64 // TODO: remove
SectorType abi.RegisteredProof
@ -37,7 +37,8 @@ type SectorInfo struct {
Pieces []Piece
// PreCommit1
Ticket api.SealTicket
TicketValue abi.SealRandomness
TicketEpoch abi.ChainEpoch
PreCommit1Out storage.PreCommit1Out
// PreCommit2
@ -48,7 +49,8 @@ type SectorInfo struct {
PreCommitMessage *cid.Cid
// WaitSeed
Seed api.SealSeed
SeedValue abi.InteractiveSealRandomness
SeedEpoch abi.ChainEpoch
// Committing
CommitMessage *cid.Cid

View File

@ -4,12 +4,11 @@ import (
"bytes"
"testing"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin"
"gotest.tools/assert"
cborutil "github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin"
)
func TestSectorInfoSelialization(t *testing.T) {
@ -29,12 +28,11 @@ func TestSectorInfoSelialization(t *testing.T) {
CommD: &dummyCid,
CommR: nil,
Proof: nil,
Ticket: api.SealTicket{
Epoch: 345,
Value: []byte{87, 78, 7, 87},
},
TicketValue: []byte{87, 78, 7, 87},
TicketEpoch: 345,
PreCommitMessage: nil,
Seed: api.SealSeed{},
SeedValue: []byte{},
SeedEpoch: 0,
CommitMessage: nil,
FaultReportMsg: nil,
LastErr: "hi",
@ -56,7 +54,8 @@ func TestSectorInfoSelialization(t *testing.T) {
assert.Equal(t, si.Pieces, si2.Pieces)
assert.Equal(t, si.CommD, si2.CommD)
assert.Equal(t, si.Ticket, si2.Ticket)
assert.Equal(t, si.TicketValue, si2.TicketValue)
assert.Equal(t, si.TicketEpoch, si2.TicketEpoch)
assert.Equal(t, si, si2)

View File

@ -1,8 +1,9 @@
package sealing
import (
"github.com/filecoin-project/specs-actors/actors/abi"
"math/bits"
"github.com/filecoin-project/specs-actors/actors/abi"
)
func fillersFromRem(in abi.UnpaddedPieceSize) ([]abi.UnpaddedPieceSize, error) {