diff --git a/storage/pipeline/commit_batch.go b/storage/pipeline/commit_batch.go index e7d89076f49..ba09ef38f50 100644 --- a/storage/pipeline/commit_batch.go +++ b/storage/pipeline/commit_batch.go @@ -16,6 +16,7 @@ import ( actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/builtin" + verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/go-state-types/proof" @@ -46,6 +47,7 @@ type CommitBatcherApi interface { StateMinerInitialPledgeCollateral(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (big.Int, error) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (network.Version, error) StateMinerAvailableBalance(context.Context, address.Address, types.TipSetKey) (big.Int, error) + StateGetAllocation(ctx context.Context, clientAddr address.Address, allocationId verifregtypes.AllocationId, tsk types.TipSetKey) (*verifregtypes.Allocation, error) // Address selector WalletBalance(context.Context, address.Address) (types.BigInt, error) @@ -348,6 +350,11 @@ func (b *CommitBatcher) processBatchV2(cfg sealiface.Config, sectors []abi.Secto infos := make([]proof.AggregateSealVerifyInfo, 0, total) collateral := big.Zero() + mid, err := address.IDFromAddress(b.maddr) + if err != nil { + return nil, err + } + for _, sector := range sectors { if b.todo[sector].DealIDPrecommit { // can't process sectors precommitted with deal IDs with ProveCommitSectors2 @@ -364,6 +371,20 @@ func (b *CommitBatcher) processBatchV2(cfg sealiface.Config, sectors []abi.Secto collateral = big.Add(collateral, sc) + manifest := b.todo[sector].ActivationManifest + if len(manifest.Pieces) > 0 { + precomitInfo, err := b.api.StateSectorPreCommitInfo(b.mctx, b.maddr, sector, ts.Key()) + if err != nil { + res.FailedSectors[sector] = err.Error() + continue + } + err = b.allocationCheck(manifest.Pieces, precomitInfo, abi.ActorID(mid), ts) + if err != nil { + res.FailedSectors[sector] = err.Error() + continue + } + } + params.SectorActivations = append(params.SectorActivations, b.todo[sector].ActivationManifest) params.SectorProofs = append(params.SectorProofs, b.todo[sector].Proof) @@ -901,3 +922,38 @@ func (b *CommitBatcher) aggregateProofType(nv network.Version) (abi.RegisteredAg } return abi.RegisteredAggregationProof_SnarkPackV2, nil } + +func (b *CommitBatcher) allocationCheck(Pieces []miner.PieceActivationManifest, precomitInfo *miner.SectorPreCommitOnChainInfo, miner abi.ActorID, ts *types.TipSet) error { + for _, p := range Pieces { + p := p + // skip pieces not claiming an allocation + if p.VerifiedAllocationKey == nil { + continue + } + addr, err := address.NewIDAddress(uint64(p.VerifiedAllocationKey.Client)) + if err != nil { + return err + } + + alloc, err := b.api.StateGetAllocation(b.mctx, addr, verifregtypes.AllocationId(p.VerifiedAllocationKey.ID), ts.Key()) + if err != nil { + return err + } + if alloc == nil { + return xerrors.Errorf("no allocation found for piece %s with allocation ID %d", p.CID.String(), p.VerifiedAllocationKey.ID) + } + if alloc.Provider != miner { + return xerrors.Errorf("provider id mismatch for piece %s: expected %d and found %d", p.CID.String(), miner, alloc.Provider) + } + if alloc.Size != p.Size { + return xerrors.Errorf("size mismatch for piece %s: expected %d and found %d", p.CID.String(), p.Size, alloc.Size) + } + if precomitInfo.Info.Expiration < ts.Height()+alloc.TermMin { + return xerrors.Errorf("sector expiration %d is before than allocation TermMin %d for piece %s", precomitInfo.Info.Expiration, ts.Height()+alloc.TermMin, p.CID.String()) + } + if precomitInfo.Info.Expiration > ts.Height()+alloc.TermMax { + return xerrors.Errorf("sector expiration %d is later than allocation TermMax %d for piece %s", precomitInfo.Info.Expiration, ts.Height()+alloc.TermMax, p.CID.String()) + } + } + return nil +} diff --git a/storage/pipeline/mocks/mock_commit_batcher.go b/storage/pipeline/mocks/mock_commit_batcher.go index 431a47c73d9..e2fce1eca01 100644 --- a/storage/pipeline/mocks/mock_commit_batcher.go +++ b/storage/pipeline/mocks/mock_commit_batcher.go @@ -14,6 +14,7 @@ import ( abi "github.com/filecoin-project/go-state-types/abi" big "github.com/filecoin-project/go-state-types/big" miner "github.com/filecoin-project/go-state-types/builtin/v9/miner" + verifreg "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" network "github.com/filecoin-project/go-state-types/network" api "github.com/filecoin-project/lotus/api" @@ -103,6 +104,21 @@ func (mr *MockCommitBatcherApiMockRecorder) StateAccountKey(arg0, arg1, arg2 int return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateAccountKey", reflect.TypeOf((*MockCommitBatcherApi)(nil).StateAccountKey), arg0, arg1, arg2) } +// StateGetAllocation mocks base method. +func (m *MockCommitBatcherApi) StateGetAllocation(arg0 context.Context, arg1 address.Address, arg2 verifreg.AllocationId, arg3 types.TipSetKey) (*verifreg.Allocation, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StateGetAllocation", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*verifreg.Allocation) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StateGetAllocation indicates an expected call of StateGetAllocation. +func (mr *MockCommitBatcherApiMockRecorder) StateGetAllocation(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateGetAllocation", reflect.TypeOf((*MockCommitBatcherApi)(nil).StateGetAllocation), arg0, arg1, arg2, arg3) +} + // StateLookupID mocks base method. func (m *MockCommitBatcherApi) StateLookupID(arg0 context.Context, arg1 address.Address, arg2 types.TipSetKey) (address.Address, error) { m.ctrl.T.Helper()