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/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/dline" "github.com/filecoin-project/go-state-types/network" market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market" market5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/market" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/blockstore" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/builtin/market" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" ) var _ sealing.SealingAPI = new(SealingAPIAdapter) type SealingAPIAdapter struct { delegate storageMinerApi } func NewSealingAPIAdapter(api storageMinerApi) SealingAPIAdapter { return SealingAPIAdapter{delegate: api} } func (s SealingAPIAdapter) StateMinerSectorSize(ctx context.Context, maddr address.Address, tok sealing.TipSetToken) (abi.SectorSize, error) { // TODO: update storage-fsm to just StateMinerInfo mi, err := s.StateMinerInfo(ctx, maddr, tok) if err != nil { return 0, err } return mi.SectorSize, nil } func (s SealingAPIAdapter) StateMinerPreCommitDepositForPower(ctx context.Context, a address.Address, pci miner.SectorPreCommitInfo, tok sealing.TipSetToken) (big.Int, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { return big.Zero(), xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) } return s.delegate.StateMinerPreCommitDepositForPower(ctx, a, pci, tsk) } func (s SealingAPIAdapter) StateMinerInitialPledgeCollateral(ctx context.Context, a address.Address, pci miner.SectorPreCommitInfo, tok sealing.TipSetToken) (big.Int, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { return big.Zero(), xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) } return s.delegate.StateMinerInitialPledgeCollateral(ctx, a, pci, tsk) } func (s SealingAPIAdapter) StateMinerInfo(ctx context.Context, maddr address.Address, tok sealing.TipSetToken) (miner.MinerInfo, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { return miner.MinerInfo{}, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) } // TODO: update storage-fsm to just StateMinerInfo return s.delegate.StateMinerInfo(ctx, maddr, tsk) } func (s SealingAPIAdapter) StateMinerWorkerAddress(ctx context.Context, maddr address.Address, tok sealing.TipSetToken) (address.Address, error) { // TODO: update storage-fsm to just StateMinerInfo mi, err := s.StateMinerInfo(ctx, maddr, tok) if err != nil { return address.Undef, err } return mi.Worker, nil } func (s SealingAPIAdapter) StateMinerDeadlines(ctx context.Context, maddr address.Address, tok sealing.TipSetToken) ([]api.Deadline, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { return nil, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) } return s.delegate.StateMinerDeadlines(ctx, maddr, tsk) } func (s SealingAPIAdapter) StateMinerSectorAllocated(ctx context.Context, maddr address.Address, sid abi.SectorNumber, tok sealing.TipSetToken) (bool, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { return false, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) } return s.delegate.StateMinerSectorAllocated(ctx, maddr, sid, tsk) } func (s SealingAPIAdapter) StateWaitMsg(ctx context.Context, mcid cid.Cid) (sealing.MsgLookup, error) { wmsg, err := s.delegate.StateWaitMsg(ctx, mcid, build.MessageConfidence) 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.Bytes(), Height: wmsg.Height, }, nil } func (s SealingAPIAdapter) StateSearchMsg(ctx context.Context, c cid.Cid) (*sealing.MsgLookup, error) { wmsg, err := s.delegate.StateSearchMsg(ctx, c) if err != nil { return nil, err } if wmsg == nil { return nil, nil } return &sealing.MsgLookup{ Receipt: sealing.MessageReceipt{ ExitCode: wmsg.Receipt.ExitCode, Return: wmsg.Receipt.Return, GasUsed: wmsg.Receipt.GasUsed, }, TipSetTok: wmsg.TipSet.Bytes(), Height: wmsg.Height, }, nil } func (s SealingAPIAdapter) StateComputeDataCommitment(ctx context.Context, maddr address.Address, sectorType abi.RegisteredSealProof, 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) } ts, err := s.delegate.ChainGetTipSet(ctx, tsk) if err != nil { return cid.Cid{}, err } // using parent ts because the migration won't be run on the first nv13 // tipset we apply StateCall to (because we don't run migrations in StateCall // and just apply to parent state) nv, err := s.delegate.StateNetworkVersion(ctx, ts.Parents()) if err != nil { return cid.Cid{}, err } var ccparams []byte if nv < network.Version13 { ccparams, err = actors.SerializeParams(&market2.ComputeDataCommitmentParams{ DealIDs: deals, SectorType: sectorType, }) } else { ccparams, err = actors.SerializeParams(&market5.ComputeDataCommitmentParams{ Inputs: []*market5.SectorDataSpec{ { DealIDs: deals, SectorType: sectorType, }, }, }) } if err != nil { return cid.Undef, xerrors.Errorf("computing params for ComputeDataCommitment: %w", err) } ccmt := &types.Message{ To: market.Address, From: maddr, Value: types.NewInt(0), Method: market.Methods.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) } if nv < network.Version13 { 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 } var cr market5.ComputeDataCommitmentReturn if err := cr.UnmarshalCBOR(bytes.NewReader(r.MsgRct.Return)); err != nil { return cid.Undef, xerrors.Errorf("failed to unmarshal CBOR to CborCid: %w", err) } if len(cr.CommDs) != 1 { return cid.Undef, xerrors.Errorf("CommD output must have 1 entry") } return cid.Cid(cr.CommDs[0]), nil } func (s SealingAPIAdapter) StateSectorPreCommitInfo(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) } stor := store.ActorStore(ctx, blockstore.NewAPIBlockstore(s.delegate)) state, err := miner.Load(stor, act) if err != nil { return nil, xerrors.Errorf("handleSealFailed(%d): temp error: loading miner state: %+v", sectorNumber, err) } pci, err := state.GetPrecommittedSector(sectorNumber) if err != nil { return nil, err } if pci == nil { set, err := state.IsAllocated(sectorNumber) if err != nil { return nil, xerrors.Errorf("checking if sector is allocated: %w", err) } if set { return nil, sealing.ErrSectorAllocated } return nil, nil } return pci, nil } func (s SealingAPIAdapter) StateSectorGetInfo(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok sealing.TipSetToken) (*miner.SectorOnChainInfo, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { return nil, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) } return s.delegate.StateSectorGetInfo(ctx, maddr, sectorNumber, tsk) } func (s SealingAPIAdapter) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok sealing.TipSetToken) (*sealing.SectorLocation, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { return nil, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) } l, err := s.delegate.StateSectorPartition(ctx, maddr, sectorNumber, tsk) if err != nil { return nil, err } if l != nil { return &sealing.SectorLocation{ Deadline: l.Deadline, Partition: l.Partition, }, nil } return nil, nil // not found } func (s SealingAPIAdapter) StateMinerPartitions(ctx context.Context, maddr address.Address, dlIdx uint64, tok sealing.TipSetToken) ([]api.Partition, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { return nil, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) } return s.delegate.StateMinerPartitions(ctx, maddr, dlIdx, tsk) } func (s SealingAPIAdapter) StateLookupID(ctx context.Context, addr address.Address, tok sealing.TipSetToken) (address.Address, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { return address.Undef, err } return s.delegate.StateLookupID(ctx, addr, tsk) } func (s SealingAPIAdapter) StateMarketStorageDeal(ctx context.Context, dealID abi.DealID, tok sealing.TipSetToken) (*api.MarketDeal, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { return nil, err } return s.delegate.StateMarketStorageDeal(ctx, dealID, tsk) } func (s SealingAPIAdapter) StateMarketStorageDealProposal(ctx context.Context, dealID abi.DealID, tok sealing.TipSetToken) (market.DealProposal, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { return market.DealProposal{}, err } deal, err := s.delegate.StateMarketStorageDeal(ctx, dealID, tsk) if err != nil { return market.DealProposal{}, err } return deal.Proposal, nil } func (s SealingAPIAdapter) StateNetworkVersion(ctx context.Context, tok sealing.TipSetToken) (network.Version, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { return network.VersionMax, err } return s.delegate.StateNetworkVersion(ctx, tsk) } func (s SealingAPIAdapter) StateMinerProvingDeadline(ctx context.Context, maddr address.Address, tok sealing.TipSetToken) (*dline.Info, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { return nil, err } return s.delegate.StateMinerProvingDeadline(ctx, maddr, tsk) } func (s SealingAPIAdapter) SendMsg(ctx context.Context, from, to address.Address, method abi.MethodNum, value, maxFee abi.TokenAmount, params []byte) (cid.Cid, error) { msg := types.Message{ To: to, From: from, Value: value, Method: method, Params: params, } smsg, err := s.delegate.MpoolPushMessage(ctx, &msg, &api.MessageSendSpec{MaxFee: maxFee}) 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) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) { return s.delegate.ChainGetMessage(ctx, mc) } func (s SealingAPIAdapter) ChainGetRandomnessFromBeacon(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.ChainGetRandomnessFromBeacon(ctx, tsk, personalization, randEpoch, entropy) } func (s SealingAPIAdapter) ChainGetRandomnessFromTickets(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.ChainGetRandomnessFromTickets(ctx, tsk, personalization, randEpoch, entropy) } func (s SealingAPIAdapter) ChainReadObj(ctx context.Context, ocid cid.Cid) ([]byte, error) { return s.delegate.ChainReadObj(ctx, ocid) }