From 0af9888b129f8902d7ae6b10f84fbda4864a4de1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 4 Oct 2022 18:12:25 +0000 Subject: [PATCH 1/4] sealing pipeline: Prepare deal assigning logic for FIP-45 --- storage/pipeline/input.go | 206 ++++++++++++++++++++++++++---------- storage/pipeline/sealing.go | 32 ++++-- 2 files changed, 174 insertions(+), 64 deletions(-) diff --git a/storage/pipeline/input.go b/storage/pipeline/input.go index 824fee255..52b601547 100644 --- a/storage/pipeline/input.go +++ b/storage/pipeline/input.go @@ -12,6 +12,7 @@ import ( "github.com/filecoin-project/go-padreader" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/go-statemachine" "github.com/filecoin-project/lotus/api" @@ -28,8 +29,13 @@ import ( func (m *Sealing) handleWaitDeals(ctx statemachine.Context, sector SectorInfo) error { var used abi.UnpaddedPieceSize + var lastDealEnd abi.ChainEpoch for _, piece := range sector.Pieces { used += piece.Piece.Size.Unpadded() + + if piece.DealInfo.DealProposal.EndEpoch > lastDealEnd { + lastDealEnd = piece.DealInfo.DealProposal.EndEpoch + } } m.inputLk.Lock() @@ -72,6 +78,7 @@ func (m *Sealing) handleWaitDeals(ctx statemachine.Context, sector SectorInfo) e // (note that m.assignedPieces[sid] will always be empty here) m.openSectors[sid].used = used } + m.openSectors[sid].lastDealEnd = lastDealEnd go func() { defer m.inputLk.Unlock() @@ -314,6 +321,8 @@ func (m *Sealing) SectorAddPieceToAny(ctx context.Context, size abi.UnpaddedPiec deal.DealProposal.PieceCID, ts.Height(), deal.DealProposal.StartEpoch) } + claimTerms, err := m.getClaimTerms(ctx, deal) + m.inputLk.Lock() if pp, exist := m.pendingPieces[proposalCID(deal)]; exist { m.inputLk.Unlock() @@ -332,7 +341,7 @@ func (m *Sealing) SectorAddPieceToAny(ctx context.Context, size abi.UnpaddedPiec } // addPendingPiece takes over m.inputLk - pp := m.addPendingPiece(ctx, size, data, deal, sp) + pp := m.addPendingPiece(ctx, size, data, deal, claimTerms, sp) res, err := waitAddPieceResp(ctx, pp) if err != nil { @@ -341,14 +350,25 @@ func (m *Sealing) SectorAddPieceToAny(ctx context.Context, size abi.UnpaddedPiec return api.SectorOffset{Sector: res.sn, Offset: res.offset.Padded()}, res.err } +func (m *Sealing) getClaimTerms(ctx context.Context, deal api.PieceDealInfo) (pieceClaimBounds, error) { + // TODO: TODO! TODO! get the real claim bounds here + + return pieceClaimBounds{ + claimTermEnd: deal.DealProposal.EndEpoch + policy.GetSectorMaxLifetime(abi.RegisteredSealProof_StackedDrg32GiBV1_1, network.Version17), + }, nil +} + // called with m.inputLk; transfers the lock to another goroutine! -func (m *Sealing) addPendingPiece(ctx context.Context, size abi.UnpaddedPieceSize, data storiface.Data, deal api.PieceDealInfo, sp abi.RegisteredSealProof) *pendingPiece { +func (m *Sealing) addPendingPiece(ctx context.Context, size abi.UnpaddedPieceSize, data storiface.Data, deal api.PieceDealInfo, ct pieceClaimBounds, sp abi.RegisteredSealProof) *pendingPiece { doneCh := make(chan struct{}) pp := &pendingPiece{ + size: size, + deal: deal, + claimTerms: ct, + + data: data, + doneCh: doneCh, - size: size, - deal: deal, - data: data, assigned: false, } pp.accepted = func(sn abi.SectorNumber, offset abi.UnpaddedPieceSize, err error) { @@ -420,6 +440,9 @@ func (m *Sealing) updateInput(ctx context.Context, sp abi.RegisteredSealProof) e sector abi.SectorID deal cid.Cid + dealEnd abi.ChainEpoch + claimTermEnd abi.ChainEpoch + size abi.UnpaddedPieceSize padding abi.UnpaddedPieceSize } @@ -440,13 +463,15 @@ func (m *Sealing) updateInput(ctx context.Context, sp abi.RegisteredSealProof) e avail := abi.PaddedPieceSize(ssize).Unpadded() - sector.used // check that sector lifetime is long enough to fit deal using latest expiration from on chain - ok, err := sector.dealFitsInLifetime(piece.deal.DealProposal.EndEpoch, getExpirationCached) + ok, err := sector.checkDealAssignable(piece, getExpirationCached) if err != nil { log.Errorf("failed to check expiration for cc Update sector %d", sector.number) continue } if !ok { exp, _, _ := getExpirationCached(sector.number) + + // todo move this log into checkDealAssignable, make more detailed about the reason log.Debugf("CC update sector %d cannot fit deal, expiration %d before deal end epoch %d", id, exp, piece.deal.DealProposal.EndEpoch) continue } @@ -456,6 +481,9 @@ func (m *Sealing) updateInput(ctx context.Context, sp abi.RegisteredSealProof) e sector: id, deal: proposalCid, + dealEnd: piece.deal.DealProposal.EndEpoch, + claimTermEnd: piece.claimTerms.claimTermEnd, + size: piece.size, padding: avail % piece.size, }) @@ -463,6 +491,8 @@ func (m *Sealing) updateInput(ctx context.Context, sp abi.RegisteredSealProof) e } } sort.Slice(matches, func(i, j int) bool { + // todo maybe sort by expiration + if matches[i].padding != matches[j].padding { // less padding is better return matches[i].padding < matches[j].padding } @@ -487,18 +517,29 @@ func (m *Sealing) updateInput(ctx context.Context, sp abi.RegisteredSealProof) e continue } + // late checks + avail := abi.PaddedPieceSize(ssize).Unpadded() - m.openSectors[mt.sector].used if mt.size > avail { continue } + if m.openSectors[mt.sector].lastDealEnd > mt.claimTermEnd { + continue + } + + // assign the piece! + err := m.openSectors[mt.sector].maybeAccept(mt.deal) if err != nil { m.pendingPieces[mt.deal].accepted(mt.sector.Number, 0, err) // non-error case in handleAddPiece } m.openSectors[mt.sector].used += mt.padding + mt.size + if mt.dealEnd > m.openSectors[mt.sector].lastDealEnd { + m.openSectors[mt.sector].lastDealEnd = mt.dealEnd + } m.pendingPieces[mt.deal].assigned = true delete(toAssign, mt.deal) @@ -521,62 +562,66 @@ func (m *Sealing) updateInput(ctx context.Context, sp abi.RegisteredSealProof) e return nil } -func (m *Sealing) calcTargetExpiration(ctx context.Context, ssize abi.SectorSize, cfg sealiface.Config) (minExpEpoch, targetEpoch abi.ChainEpoch, err error) { - var candidates []*pendingPiece +// pendingPieceIndex is an index in the Sealing.pendingPieces map +type pendingPieceIndex cid.Cid - for _, piece := range m.pendingPieces { - if piece.assigned { - continue // already assigned to a sector, skip +type pieceBound struct { + epoch abi.ChainEpoch + + // boundStart marks deal /end/ epoch; only deals with boundStart lower or equal to expiration of a given sector can be + // put into that sector + boundStart []pendingPieceIndex + + // boundEnd marks deal claim TermMax; only deals with boundEnd higher or equal to expiration of a given sector can be + // put into that sector + boundEnd []pendingPieceIndex + + dealBytesInBound abi.UnpaddedPieceSize +} + +func (m *Sealing) pendingPieceEpochBounds() []pieceBound { + boundsByEpoch := map[abi.ChainEpoch]*pieceBound{} + + for ppi, piece := range m.pendingPieces { + // start bound on deal end + if boundsByEpoch[piece.deal.DealProposal.EndEpoch] == nil { + boundsByEpoch[piece.deal.DealProposal.EndEpoch] = &pieceBound{ + epoch: piece.deal.DealProposal.EndEpoch, + } } - candidates = append(candidates, piece) + boundsByEpoch[piece.deal.DealProposal.EndEpoch].boundStart = append(boundsByEpoch[piece.deal.DealProposal.EndEpoch].boundStart, pendingPieceIndex(ppi)) + + // end bound on term max + if boundsByEpoch[piece.claimTerms.claimTermEnd] == nil { + boundsByEpoch[piece.claimTerms.claimTermEnd] = &pieceBound{ + epoch: piece.claimTerms.claimTermEnd, + } + } + boundsByEpoch[piece.claimTerms.claimTermEnd].boundEnd = append(boundsByEpoch[piece.claimTerms.claimTermEnd].boundEnd, pendingPieceIndex(ppi)) } - // earliest expiration first - sort.Slice(candidates, func(i, j int) bool { - return candidates[i].deal.DealProposal.EndEpoch < candidates[j].deal.DealProposal.EndEpoch + out := make([]pieceBound, 0, len(boundsByEpoch)) + for _, bound := range boundsByEpoch { + out = append(out, *bound) + } + + sort.Slice(out, func(i, j int) bool { + return out[i].epoch < out[j].epoch }) - var totalBytes uint64 - var full bool - - // Find the expiration of the last deal which can fit into the sector, use that as the initial target - for _, candidate := range candidates { - totalBytes += uint64(candidate.size) - targetEpoch = candidate.deal.DealProposal.EndEpoch - - if totalBytes >= uint64(abi.PaddedPieceSize(ssize).Unpadded()) { - full = true - break + var curBoundBytes abi.UnpaddedPieceSize + for i, bound := range out { + for _, ppi := range bound.boundStart { + curBoundBytes += m.pendingPieces[cid.Cid(ppi)].size } + for _, ppi := range bound.boundEnd { + curBoundBytes -= m.pendingPieces[cid.Cid(ppi)].size + } + + out[i].dealBytesInBound = curBoundBytes } - ts, err := m.Api.ChainHead(ctx) - if err != nil { - return 0, 0, xerrors.Errorf("getting current epoch: %w", err) - } - - // if the sector isn't full, use max deal duration as the target - if !full { - minDur, maxDur := policy.DealDurationBounds(0) - - minExpEpoch = ts.Height() + minDur - targetEpoch = ts.Height() + maxDur - } - - // make sure that at least one deal in the queue is within the expiration - if len(candidates) > 0 && candidates[0].deal.DealProposal.EndEpoch > minExpEpoch { - minExpEpoch = candidates[0].deal.DealProposal.EndEpoch - } - - // apply user minimums - if abi.ChainEpoch(cfg.MinUpgradeSectorExpiration)+ts.Height() > minExpEpoch { - minExpEpoch = abi.ChainEpoch(cfg.MinUpgradeSectorExpiration) + ts.Height() - } - if abi.ChainEpoch(cfg.MinTargetUpgradeSectorExpiration)+ts.Height() > targetEpoch { - targetEpoch = abi.ChainEpoch(cfg.MinTargetUpgradeSectorExpiration) + ts.Height() - } - - return minExpEpoch, targetEpoch, nil + return out } func (m *Sealing) maybeUpgradeSector(ctx context.Context, sp abi.RegisteredSealProof, cfg sealiface.Config, ef expFn) (bool, error) { @@ -584,17 +629,37 @@ func (m *Sealing) maybeUpgradeSector(ctx context.Context, sp abi.RegisteredSealP return false, nil } + ts, err := m.Api.ChainHead(ctx) + if err != nil { + return false, err + } ssize, err := sp.SectorSize() if err != nil { - return false, xerrors.Errorf("getting sector size: %w", err) + return false, err } - minExpirationEpoch, targetExpirationEpoch, err := m.calcTargetExpiration(ctx, ssize, cfg) - if err != nil { - return false, xerrors.Errorf("calculating min target expiration: %w", err) + + pieceBounds := m.pendingPieceEpochBounds() + + findBound := func(sectorExp abi.ChainEpoch) *pieceBound { + if len(pieceBounds) == 0 { + return nil + } + f := sort.Search(len(pieceBounds), func(i int) bool { + return sectorExp <= pieceBounds[i].epoch + }) + if f == 0 { + // all piece bounds are after sector expiration + return nil + } + return &pieceBounds[f-1] } + targetExpirationEpoch := ts.Height() + abi.ChainEpoch(cfg.MinTargetUpgradeSectorExpiration) + minExpirationEpoch := ts.Height() + abi.ChainEpoch(cfg.MinUpgradeSectorExpiration) + var candidate abi.SectorID var bestExpiration abi.ChainEpoch + var bestDealBytes abi.PaddedPieceSize bestPledge := types.TotalFilecoinInt for s := range m.available { @@ -611,19 +676,43 @@ func (m *Sealing) maybeUpgradeSector(ctx context.Context, sp abi.RegisteredSealP return false } if !active { - log.Debugw("skipping available sector", "reason", "not active") + log.Debugw("skipping available sector", "sector", sid, "reason", "not active") return false } return true } + if expirationEpoch < minExpirationEpoch { + log.Debugw("skipping available sector", "sector", s.Number, "reason", "expiration below MinUpgradeSectorExpiration") + } + + pb := findBound(expirationEpoch) + if pb == nil { + log.Debugw("skipping available sector", "sector", s.Number, "reason", "expiration below deal bounds") + continue + } + + // if the sector has less than one sector worth of candidate deals, and + // the best candidate has more candidate deals, this sector isn't better + if pb.dealBytesInBound.Padded() < abi.PaddedPieceSize(ssize) { + if bestDealBytes > pb.dealBytesInBound.Padded() { + continue + } + } + // if best is below target, we want larger expirations // if best is above target, we want lower pledge, but only if still above target + // todo: after nv17 "target expiration" doesn't really make that much sense + // (tho to be fair it doesn't make too much sense now either) + // we probably want the lowest expiration that's still above the configured + // minimum, and has can fit most candidate deals + if bestExpiration < targetExpirationEpoch { if expirationEpoch > bestExpiration && slowChecks(s.Number) { bestExpiration = expirationEpoch bestPledge = pledge + bestDealBytes = pb.dealBytesInBound.Padded() candidate = s } continue @@ -632,6 +721,7 @@ func (m *Sealing) maybeUpgradeSector(ctx context.Context, sp abi.RegisteredSealP if expirationEpoch >= targetExpirationEpoch && pledge.LessThan(bestPledge) && slowChecks(s.Number) { bestExpiration = expirationEpoch bestPledge = pledge + bestDealBytes = pb.dealBytesInBound.Padded() candidate = s } } diff --git a/storage/pipeline/sealing.go b/storage/pipeline/sealing.go index 153a4cc32..aac8cd8dd 100644 --- a/storage/pipeline/sealing.go +++ b/storage/pipeline/sealing.go @@ -131,22 +131,35 @@ type Sealing struct { } type openSector struct { - used abi.UnpaddedPieceSize // change to bitfield/rle when AddPiece gains offset support to better fill sectors - number abi.SectorNumber - ccUpdate bool + used abi.UnpaddedPieceSize // change to bitfield/rle when AddPiece gains offset support to better fill sectors + lastDealEnd abi.ChainEpoch + number abi.SectorNumber + ccUpdate bool maybeAccept func(cid.Cid) error // called with inputLk } -func (o *openSector) dealFitsInLifetime(dealEnd abi.ChainEpoch, expF expFn) (bool, error) { +func (o *openSector) checkDealAssignable(piece *pendingPiece, expF expFn) (bool, error) { + // if there are deals assigned, check that no assigned deal expires after termMax + if o.lastDealEnd > piece.claimTerms.claimTermEnd { + return false, nil + } + + // check that in case of upgrade sectors, sector expiration is at least deal expiration if !o.ccUpdate { return true, nil } - expiration, _, err := expF(o.number) + sectorExpiration, _, err := expF(o.number) if err != nil { return false, err } - return expiration >= dealEnd, nil + + // check that in case of upgrade sector, it's expiration isn't above deals claim TermMax + if sectorExpiration > piece.claimTerms.claimTermEnd { + return false, nil + } + + return sectorExpiration >= piece.deal.DealProposal.EndEpoch, nil } type pieceAcceptResp struct { @@ -155,6 +168,11 @@ type pieceAcceptResp struct { err error } +type pieceClaimBounds struct { + // dealStart + termMax + claimTermEnd abi.ChainEpoch +} + type pendingPiece struct { doneCh chan struct{} resp *pieceAcceptResp @@ -162,6 +180,8 @@ type pendingPiece struct { size abi.UnpaddedPieceSize deal api.PieceDealInfo + claimTerms pieceClaimBounds + data storiface.Data assigned bool // assigned to a sector? From dc102f076a29cf6239d5f420bbcdadb6ce8e8bbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 10 Oct 2022 19:31:48 +0200 Subject: [PATCH 2/4] sealing pipeline: Get allocationId with StateApi --- api/api_full.go | 3 +- build/openrpc/full.json.gz | Bin 28998 -> 29022 bytes chain/actors/builtin/market/actor.go.template | 2 +- chain/actors/builtin/market/market.go | 2 +- chain/actors/builtin/market/state.go.template | 14 +++++---- chain/actors/builtin/market/v0.go | 4 +-- chain/actors/builtin/market/v2.go | 4 +-- chain/actors/builtin/market/v3.go | 4 +-- chain/actors/builtin/market/v4.go | 4 +-- chain/actors/builtin/market/v5.go | 4 +-- chain/actors/builtin/market/v6.go | 4 +-- chain/actors/builtin/market/v7.go | 4 +-- chain/actors/builtin/market/v8.go | 4 +-- chain/actors/builtin/market/v9.go | 12 ++++---- documentation/en/api-v1-unstable-methods.md | 3 +- node/impl/full/state.go | 5 +++- storage/pipeline/input.go | 27 +++++++++++++++--- storage/pipeline/mocks/api.go | 16 +++++++++++ storage/pipeline/sealing.go | 2 ++ 19 files changed, 82 insertions(+), 36 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index 1ec1c22be..320a20687 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -528,7 +528,8 @@ type FullNode interface { StateMarketDeals(context.Context, types.TipSetKey) (map[string]*MarketDeal, error) //perm:read // StateMarketStorageDeal returns information about the indicated deal StateMarketStorageDeal(context.Context, abi.DealID, types.TipSetKey) (*MarketDeal, error) //perm:read - // StateGetAllocationForPendingDeal returns the allocation for a given deal ID of a pending deal. + // StateGetAllocationForPendingDeal returns the allocation for a given deal ID of a pending deal. Returns nil if + // pending allocation is not found. StateGetAllocationForPendingDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*verifregtypes.Allocation, error) //perm:read // StateGetAllocation returns the allocation for a given address and allocation ID. StateGetAllocation(ctx context.Context, clientAddr address.Address, allocationId verifregtypes.AllocationId, tsk types.TipSetKey) (*verifregtypes.Allocation, error) //perm:read diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index aec7b5f315134bc1e1a67bcee9a74b92f68a5c1d..20862916a7cff5e91b074dcb5e4e58731752cb02 100644 GIT binary patch delta 10070 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 network.Version17 { + all, err := m.Api.StateGetAllocationForPendingDeal(ctx, deal.DealID, tsk) + if err != nil { + return pieceClaimBounds{}, err + } + if all != nil { + return pieceClaimBounds{ + claimTermEnd: deal.DealProposal.StartEpoch + all.TermMax, + }, nil + } + } + + // no allocation for this deal, so just use a really high number for "term end" return pieceClaimBounds{ claimTermEnd: deal.DealProposal.EndEpoch + policy.GetSectorMaxLifetime(abi.RegisteredSealProof_StackedDrg32GiBV1_1, network.Version17), }, nil @@ -706,7 +725,7 @@ func (m *Sealing) maybeUpgradeSector(ctx context.Context, sp abi.RegisteredSealP // todo: after nv17 "target expiration" doesn't really make that much sense // (tho to be fair it doesn't make too much sense now either) // we probably want the lowest expiration that's still above the configured - // minimum, and has can fit most candidate deals + // minimum, and can fit most candidate deals if bestExpiration < targetExpirationEpoch { if expirationEpoch > bestExpiration && slowChecks(s.Number) { diff --git a/storage/pipeline/mocks/api.go b/storage/pipeline/mocks/api.go index b6b6c7022..066fe996e 100644 --- a/storage/pipeline/mocks/api.go +++ b/storage/pipeline/mocks/api.go @@ -16,6 +16,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" crypto "github.com/filecoin-project/go-state-types/crypto" dline "github.com/filecoin-project/go-state-types/dline" network "github.com/filecoin-project/go-state-types/network" @@ -138,6 +139,21 @@ func (mr *MockSealingAPIMockRecorder) StateComputeDataCID(arg0, arg1, arg2, arg3 return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateComputeDataCID", reflect.TypeOf((*MockSealingAPI)(nil).StateComputeDataCID), arg0, arg1, arg2, arg3, arg4) } +// StateGetAllocationForPendingDeal mocks base method. +func (m *MockSealingAPI) StateGetAllocationForPendingDeal(arg0 context.Context, arg1 abi.DealID, arg2 types.TipSetKey) (*verifreg.Allocation, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StateGetAllocationForPendingDeal", arg0, arg1, arg2) + ret0, _ := ret[0].(*verifreg.Allocation) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StateGetAllocationForPendingDeal indicates an expected call of StateGetAllocationForPendingDeal. +func (mr *MockSealingAPIMockRecorder) StateGetAllocationForPendingDeal(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateGetAllocationForPendingDeal", reflect.TypeOf((*MockSealingAPI)(nil).StateGetAllocationForPendingDeal), arg0, arg1, arg2) +} + // StateGetRandomnessFromBeacon mocks base method. func (m *MockSealingAPI) StateGetRandomnessFromBeacon(arg0 context.Context, arg1 crypto.DomainSeparationTag, arg2 abi.ChainEpoch, arg3 []byte, arg4 types.TipSetKey) (abi.Randomness, error) { m.ctrl.T.Helper() diff --git a/storage/pipeline/sealing.go b/storage/pipeline/sealing.go index aac8cd8dd..6caa9ddc6 100644 --- a/storage/pipeline/sealing.go +++ b/storage/pipeline/sealing.go @@ -16,6 +16,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/builtin/v9/miner" + verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/dline" "github.com/filecoin-project/go-state-types/network" @@ -69,6 +70,7 @@ type SealingAPI interface { StateGetRandomnessFromTickets(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error) ChainReadObj(context.Context, cid.Cid) ([]byte, error) StateMinerAllocated(context.Context, address.Address, types.TipSetKey) (*bitfield.BitField, error) + StateGetAllocationForPendingDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*verifregtypes.Allocation, error) // Address selector WalletBalance(context.Context, address.Address) (types.BigInt, error) From ce17decf3b87624017316d574f008339e11f368a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 11 Oct 2022 18:31:19 +0200 Subject: [PATCH 3/4] use NoAllocationID instead of nil AllocationId --- chain/actors/builtin/market/actor.go.template | 2 +- chain/actors/builtin/market/market.go | 2 +- chain/actors/builtin/market/state.go.template | 13 ++++++------- chain/actors/builtin/market/v0.go | 4 ++-- chain/actors/builtin/market/v2.go | 4 ++-- chain/actors/builtin/market/v3.go | 4 ++-- chain/actors/builtin/market/v4.go | 4 ++-- chain/actors/builtin/market/v5.go | 4 ++-- chain/actors/builtin/market/v6.go | 4 ++-- chain/actors/builtin/market/v7.go | 4 ++-- chain/actors/builtin/market/v8.go | 4 ++-- chain/actors/builtin/market/v9.go | 11 +++++------ go.mod | 2 +- go.sum | 4 ++-- node/impl/full/state.go | 4 ++-- 15 files changed, 34 insertions(+), 36 deletions(-) diff --git a/chain/actors/builtin/market/actor.go.template b/chain/actors/builtin/market/actor.go.template index bd05bfcc6..fa0622ff0 100644 --- a/chain/actors/builtin/market/actor.go.template +++ b/chain/actors/builtin/market/actor.go.template @@ -86,7 +86,7 @@ type State interface { ) (weight, verifiedWeight abi.DealWeight, err error) NextID() (abi.DealID, error) GetState() interface{} - GetAllocationIdForPendingDeal(dealId abi.DealID) (*verifregtypes.AllocationId, error) + GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes.AllocationId, error) } type BalanceTable interface { diff --git a/chain/actors/builtin/market/market.go b/chain/actors/builtin/market/market.go index 2479964bd..0e095d282 100644 --- a/chain/actors/builtin/market/market.go +++ b/chain/actors/builtin/market/market.go @@ -127,7 +127,7 @@ type State interface { ) (weight, verifiedWeight abi.DealWeight, err error) NextID() (abi.DealID, error) GetState() interface{} - GetAllocationIdForPendingDeal(dealId abi.DealID) (*verifregtypes.AllocationId, error) + GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes.AllocationId, error) } type BalanceTable interface { diff --git a/chain/actors/builtin/market/state.go.template b/chain/actors/builtin/market/state.go.template index 0684377e9..50abdeb6b 100644 --- a/chain/actors/builtin/market/state.go.template +++ b/chain/actors/builtin/market/state.go.template @@ -366,25 +366,24 @@ func (r *publishStorageDealsReturn{{.v}}) DealIDs() ([]abi.DealID, error) { return r.IDs, nil } -func (s *state{{.v}}) GetAllocationIdForPendingDeal(dealId abi.DealID) (*verifregtypes.AllocationId, error) { +func (s *state{{.v}}) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes.AllocationId, error) { {{if (le .v 8)}} - return nil, xerrors.Errorf("unsupported before actors v9") + return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") {{else}} allocations, err := adt9.AsMap(s.store, s.PendingDealAllocationIds, builtin.DefaultHamtBitwidth) if err != nil { - return nil, xerrors.Errorf("failed to load allocation id for %d: %w", dealId, err) + return verifregtypes.NoAllocationID, xerrors.Errorf("failed to load allocation id for %d: %w", dealId, err) } var allocationId cbg.CborInt found, err := allocations.Get(abi.UIntKey(uint64(dealId)), &allocationId) if err != nil { - return nil, xerrors.Errorf("failed to load allocation id for %d: %w", dealId, err) + return verifregtypes.NoAllocationID, xerrors.Errorf("failed to load allocation id for %d: %w", dealId, err) } if !found { - return nil, nil + return verifregtypes.NoAllocationID, nil } - aid := verifregtypes.AllocationId(allocationId) - return &aid, nil + return verifregtypes.AllocationId(allocationId), nil {{end}} } diff --git a/chain/actors/builtin/market/v0.go b/chain/actors/builtin/market/v0.go index 15c9530cd..aa68049bb 100644 --- a/chain/actors/builtin/market/v0.go +++ b/chain/actors/builtin/market/v0.go @@ -302,8 +302,8 @@ func (r *publishStorageDealsReturn0) DealIDs() ([]abi.DealID, error) { return r.IDs, nil } -func (s *state0) GetAllocationIdForPendingDeal(dealId abi.DealID) (*verifregtypes.AllocationId, error) { +func (s *state0) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes.AllocationId, error) { - return nil, xerrors.Errorf("unsupported before actors v9") + return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } diff --git a/chain/actors/builtin/market/v2.go b/chain/actors/builtin/market/v2.go index c6b433865..777a17cd0 100644 --- a/chain/actors/builtin/market/v2.go +++ b/chain/actors/builtin/market/v2.go @@ -302,8 +302,8 @@ func (r *publishStorageDealsReturn2) DealIDs() ([]abi.DealID, error) { return r.IDs, nil } -func (s *state2) GetAllocationIdForPendingDeal(dealId abi.DealID) (*verifregtypes.AllocationId, error) { +func (s *state2) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes.AllocationId, error) { - return nil, xerrors.Errorf("unsupported before actors v9") + return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } diff --git a/chain/actors/builtin/market/v3.go b/chain/actors/builtin/market/v3.go index ca6f34191..5ca09fdfb 100644 --- a/chain/actors/builtin/market/v3.go +++ b/chain/actors/builtin/market/v3.go @@ -297,8 +297,8 @@ func (r *publishStorageDealsReturn3) DealIDs() ([]abi.DealID, error) { return r.IDs, nil } -func (s *state3) GetAllocationIdForPendingDeal(dealId abi.DealID) (*verifregtypes.AllocationId, error) { +func (s *state3) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes.AllocationId, error) { - return nil, xerrors.Errorf("unsupported before actors v9") + return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } diff --git a/chain/actors/builtin/market/v4.go b/chain/actors/builtin/market/v4.go index 3c17ab814..23422ec31 100644 --- a/chain/actors/builtin/market/v4.go +++ b/chain/actors/builtin/market/v4.go @@ -297,8 +297,8 @@ func (r *publishStorageDealsReturn4) DealIDs() ([]abi.DealID, error) { return r.IDs, nil } -func (s *state4) GetAllocationIdForPendingDeal(dealId abi.DealID) (*verifregtypes.AllocationId, error) { +func (s *state4) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes.AllocationId, error) { - return nil, xerrors.Errorf("unsupported before actors v9") + return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } diff --git a/chain/actors/builtin/market/v5.go b/chain/actors/builtin/market/v5.go index f7d006fdd..8e8833c37 100644 --- a/chain/actors/builtin/market/v5.go +++ b/chain/actors/builtin/market/v5.go @@ -297,8 +297,8 @@ func (r *publishStorageDealsReturn5) DealIDs() ([]abi.DealID, error) { return r.IDs, nil } -func (s *state5) GetAllocationIdForPendingDeal(dealId abi.DealID) (*verifregtypes.AllocationId, error) { +func (s *state5) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes.AllocationId, error) { - return nil, xerrors.Errorf("unsupported before actors v9") + return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } diff --git a/chain/actors/builtin/market/v6.go b/chain/actors/builtin/market/v6.go index 517c1ff87..d86f73108 100644 --- a/chain/actors/builtin/market/v6.go +++ b/chain/actors/builtin/market/v6.go @@ -315,8 +315,8 @@ func (r *publishStorageDealsReturn6) DealIDs() ([]abi.DealID, error) { return r.IDs, nil } -func (s *state6) GetAllocationIdForPendingDeal(dealId abi.DealID) (*verifregtypes.AllocationId, error) { +func (s *state6) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes.AllocationId, error) { - return nil, xerrors.Errorf("unsupported before actors v9") + return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } diff --git a/chain/actors/builtin/market/v7.go b/chain/actors/builtin/market/v7.go index 62a39814c..5f6547e3f 100644 --- a/chain/actors/builtin/market/v7.go +++ b/chain/actors/builtin/market/v7.go @@ -315,8 +315,8 @@ func (r *publishStorageDealsReturn7) DealIDs() ([]abi.DealID, error) { return r.IDs, nil } -func (s *state7) GetAllocationIdForPendingDeal(dealId abi.DealID) (*verifregtypes.AllocationId, error) { +func (s *state7) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes.AllocationId, error) { - return nil, xerrors.Errorf("unsupported before actors v9") + return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } diff --git a/chain/actors/builtin/market/v8.go b/chain/actors/builtin/market/v8.go index 22fead2ee..5f3b690bb 100644 --- a/chain/actors/builtin/market/v8.go +++ b/chain/actors/builtin/market/v8.go @@ -332,8 +332,8 @@ func (r *publishStorageDealsReturn8) DealIDs() ([]abi.DealID, error) { return r.IDs, nil } -func (s *state8) GetAllocationIdForPendingDeal(dealId abi.DealID) (*verifregtypes.AllocationId, error) { +func (s *state8) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes.AllocationId, error) { - return nil, xerrors.Errorf("unsupported before actors v9") + return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } diff --git a/chain/actors/builtin/market/v9.go b/chain/actors/builtin/market/v9.go index f1b06a5f7..9fed45ae8 100644 --- a/chain/actors/builtin/market/v9.go +++ b/chain/actors/builtin/market/v9.go @@ -328,23 +328,22 @@ func (r *publishStorageDealsReturn9) DealIDs() ([]abi.DealID, error) { return r.IDs, nil } -func (s *state9) GetAllocationIdForPendingDeal(dealId abi.DealID) (*verifregtypes.AllocationId, error) { +func (s *state9) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes.AllocationId, error) { allocations, err := adt9.AsMap(s.store, s.PendingDealAllocationIds, builtin.DefaultHamtBitwidth) if err != nil { - return nil, xerrors.Errorf("failed to load allocation id for %d: %w", dealId, err) + return verifregtypes.NoAllocationID, xerrors.Errorf("failed to load allocation id for %d: %w", dealId, err) } var allocationId cbg.CborInt found, err := allocations.Get(abi.UIntKey(uint64(dealId)), &allocationId) if err != nil { - return nil, xerrors.Errorf("failed to load allocation id for %d: %w", dealId, err) + return verifregtypes.NoAllocationID, xerrors.Errorf("failed to load allocation id for %d: %w", dealId, err) } if !found { - return nil, nil + return verifregtypes.NoAllocationID, nil } - aid := verifregtypes.AllocationId(allocationId) - return &aid, nil + return verifregtypes.AllocationId(allocationId), nil } diff --git a/go.mod b/go.mod index f3c073c70..b70ff949e 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,7 @@ require ( github.com/filecoin-project/go-legs v0.4.4 github.com/filecoin-project/go-padreader v0.0.1 github.com/filecoin-project/go-paramfetch v0.0.4 - github.com/filecoin-project/go-state-types v0.9.0-rc1 + github.com/filecoin-project/go-state-types v0.9.0-rc2 github.com/filecoin-project/go-statemachine v1.0.2 github.com/filecoin-project/go-statestore v0.2.0 github.com/filecoin-project/go-storedcounter v0.1.0 diff --git a/go.sum b/go.sum index d41f75715..91d746106 100644 --- a/go.sum +++ b/go.sum @@ -343,8 +343,8 @@ github.com/filecoin-project/go-state-types v0.1.0/go.mod h1:ezYnPf0bNkTsDibL/psS github.com/filecoin-project/go-state-types v0.1.6/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= github.com/filecoin-project/go-state-types v0.1.8/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= github.com/filecoin-project/go-state-types v0.1.10/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= -github.com/filecoin-project/go-state-types v0.9.0-rc1 h1:cK6OzKP11aIFt0fbor/lqvrzEBegbMGHnSr9LJN/r4g= -github.com/filecoin-project/go-state-types v0.9.0-rc1/go.mod h1:+HCZifUV+e8TlQkgll22Ucuiq8OrVJkK+4Kh4u75iiw= +github.com/filecoin-project/go-state-types v0.9.0-rc2 h1:HtSxHUEwAtpnhV/77/ugnUt9lwvTTcQ7PRV+5iTAcUw= +github.com/filecoin-project/go-state-types v0.9.0-rc2/go.mod h1:+HCZifUV+e8TlQkgll22Ucuiq8OrVJkK+4Kh4u75iiw= github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v1.0.2 h1:421SSWBk8GIoCoWYYTE/d+qCWccgmRH0uXotXRDjUbc= github.com/filecoin-project/go-statemachine v1.0.2/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54= diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 21aecc26b..e2c3438bb 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -786,7 +786,7 @@ func (a *StateAPI) StateGetAllocationForPendingDeal(ctx context.Context, dealId if err != nil { return nil, err } - if allocationId == nil { + if allocationId == verifregtypes.NoAllocationID { return nil, nil } @@ -795,7 +795,7 @@ func (a *StateAPI) StateGetAllocationForPendingDeal(ctx context.Context, dealId return nil, err } - return a.StateGetAllocation(ctx, dealState.Proposal.Client, *allocationId, tsk) + return a.StateGetAllocation(ctx, dealState.Proposal.Client, allocationId, tsk) } func (a *StateAPI) StateGetAllocation(ctx context.Context, clientAddr address.Address, allocationId verifregtypes.AllocationId, tsk types.TipSetKey) (*verifregtypes.Allocation, error) { From 65e37c29e492787cf4432311109733a5bf03bf8e Mon Sep 17 00:00:00 2001 From: Aayush Date: Wed, 12 Oct 2022 13:42:46 -0400 Subject: [PATCH 4/4] address review --- storage/pipeline/input.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/pipeline/input.go b/storage/pipeline/input.go index ce2e68eb4..631e84455 100644 --- a/storage/pipeline/input.go +++ b/storage/pipeline/input.go @@ -33,7 +33,7 @@ func (m *Sealing) handleWaitDeals(ctx statemachine.Context, sector SectorInfo) e for _, piece := range sector.Pieces { used += piece.Piece.Size.Unpadded() - if piece.DealInfo.DealProposal.EndEpoch > lastDealEnd { + if piece.DealInfo != nil && piece.DealInfo.DealProposal.EndEpoch > lastDealEnd { lastDealEnd = piece.DealInfo.DealProposal.EndEpoch } }