improve diff logic

* Make diffing work across versions.
* Start porting more chainwatch logic.
This commit is contained in:
Steven Allen 2020-09-17 21:39:34 -07:00
parent 5bcfee0042
commit b2ee59024f
6 changed files with 364 additions and 287 deletions

View File

@ -0,0 +1,127 @@
package miner
import (
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/chain/actors/adt"
cbg "github.com/whyrusleeping/cbor-gen"
)
func DiffPreCommits(pre, cur State) (*PreCommitChanges, error) {
results := new(PreCommitChanges)
prep, err := pre.precommits()
if err != nil {
return nil, err
}
curp, err := cur.precommits()
if err != nil {
return nil, err
}
err = adt.DiffAdtMap(prep, curp, &preCommitDiffer{results, pre, cur})
if err != nil {
return nil, err
}
return results, nil
}
type preCommitDiffer struct {
Results *PreCommitChanges
pre, after State
}
func (m *preCommitDiffer) AsKey(key string) (abi.Keyer, error) {
sector, err := abi.ParseUIntKey(key)
if err != nil {
return nil, err
}
return abi.UIntKey(sector), nil
}
func (m *preCommitDiffer) Add(key string, val *cbg.Deferred) error {
sp, err := m.after.decodeSectorPreCommitOnChainInfo(val)
if err != nil {
return err
}
m.Results.Added = append(m.Results.Added, sp)
return nil
}
func (m *preCommitDiffer) Modify(key string, from, to *cbg.Deferred) error {
return nil
}
func (m *preCommitDiffer) Remove(key string, val *cbg.Deferred) error {
sp, err := m.pre.decodeSectorPreCommitOnChainInfo(val)
if err != nil {
return err
}
m.Results.Removed = append(m.Results.Removed, sp)
return nil
}
func DiffSectors(pre, cur State) (*SectorChanges, error) {
results := new(SectorChanges)
pres, err := pre.sectors()
if err != nil {
return nil, err
}
curs, err := cur.sectors()
if err != nil {
return nil, err
}
err = adt.DiffAdtArray(pres, curs, &sectorDiffer{results, pre, cur})
if err != nil {
return nil, err
}
return results, nil
}
type sectorDiffer struct {
Results *SectorChanges
pre, after State
}
func (m *sectorDiffer) Add(key uint64, val *cbg.Deferred) error {
si, err := m.after.decodeSectorOnChainInfo(val)
if err != nil {
return err
}
m.Results.Added = append(m.Results.Added, si)
return nil
}
func (m *sectorDiffer) Modify(key uint64, from, to *cbg.Deferred) error {
siFrom, err := m.pre.decodeSectorOnChainInfo(from)
if err != nil {
return err
}
siTo, err := m.after.decodeSectorOnChainInfo(to)
if err != nil {
return err
}
if siFrom.Expiration != siTo.Expiration {
m.Results.Extended = append(m.Results.Extended, SectorExtensions{
From: siFrom,
To: siTo,
})
}
return nil
}
func (m *sectorDiffer) Remove(key uint64, val *cbg.Deferred) error {
si, err := m.pre.decodeSectorOnChainInfo(val)
if err != nil {
return err
}
m.Results.Removed = append(m.Results.Removed, si)
return nil
}

View File

@ -3,6 +3,7 @@ package miner
import ( import (
"github.com/filecoin-project/go-state-types/dline" "github.com/filecoin-project/go-state-types/dline"
"github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peer"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
@ -42,21 +43,30 @@ type State interface {
GetSectorExpiration(abi.SectorNumber) (*SectorExpiration, error) GetSectorExpiration(abi.SectorNumber) (*SectorExpiration, error)
GetPrecommittedSector(abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) GetPrecommittedSector(abi.SectorNumber) (*SectorPreCommitOnChainInfo, error)
LoadSectorsFromSet(filter *bitfield.BitField, filterOut bool) (adt.Array, error) LoadSectorsFromSet(filter *bitfield.BitField, filterOut bool) (adt.Array, error)
LoadPreCommittedSectors() (adt.Map, error)
IsAllocated(abi.SectorNumber) (bool, error) IsAllocated(abi.SectorNumber) (bool, error)
LoadDeadline(idx uint64) (Deadline, error) LoadDeadline(idx uint64) (Deadline, error)
ForEachDeadline(cb func(idx uint64, dl Deadline) error) error ForEachDeadline(cb func(idx uint64, dl Deadline) error) error
NumDeadlines() (uint64, error) NumDeadlines() (uint64, error)
DeadlinesChanged(State) bool
Info() (MinerInfo, error) Info() (MinerInfo, error)
DeadlineInfo(epoch abi.ChainEpoch) *dline.Info DeadlineInfo(epoch abi.ChainEpoch) *dline.Info
// Diff helpers. Used by Diff* functions internally.
sectors() (adt.Array, error)
decodeSectorOnChainInfo(*cbg.Deferred) (SectorOnChainInfo, error)
precommits() (adt.Map, error)
decodeSectorPreCommitOnChainInfo(*cbg.Deferred) (SectorPreCommitOnChainInfo, error)
} }
type Deadline interface { type Deadline interface {
LoadPartition(idx uint64) (Partition, error) LoadPartition(idx uint64) (Partition, error)
ForEachPartition(cb func(idx uint64, part Partition) error) error ForEachPartition(cb func(idx uint64, part Partition) error) error
PostSubmissions() (bitfield.BitField, error) PostSubmissions() (bitfield.BitField, error)
PartitionsChanged(Deadline) bool
} }
type Partition interface { type Partition interface {
@ -110,3 +120,19 @@ type SectorLocation struct {
Deadline uint64 Deadline uint64
Partition uint64 Partition uint64
} }
type SectorChanges struct {
Added []SectorOnChainInfo
Extended []SectorExtensions
Removed []SectorOnChainInfo
}
type SectorExtensions struct {
From SectorOnChainInfo
To SectorOnChainInfo
}
type PreCommitChanges struct {
Added []SectorPreCommitOnChainInfo
Removed []SectorPreCommitOnChainInfo
}

View File

@ -1,6 +1,7 @@
package miner package miner
import ( import (
"bytes"
"errors" "errors"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
@ -206,6 +207,16 @@ func (s *v0State) NumDeadlines() (uint64, error) {
return v0miner.WPoStPeriodDeadlines, nil return v0miner.WPoStPeriodDeadlines, nil
} }
func (s *v0State) DeadlinesChanged(other State) bool {
v0other, ok := other.(*v0State)
if !ok {
// treat an upgrade as a change, always
return true
}
return s.State.Deadlines.Equals(v0other.Deadlines)
}
func (s *v0State) Info() (MinerInfo, error) { func (s *v0State) Info() (MinerInfo, error) {
info, err := s.State.GetInfo(s.store) info, err := s.State.GetInfo(s.store)
if err != nil { if err != nil {
@ -244,6 +255,26 @@ func (s *v0State) DeadlineInfo(epoch abi.ChainEpoch) *dline.Info {
return s.State.DeadlineInfo(epoch) return s.State.DeadlineInfo(epoch)
} }
func (s *v0State) sectors() (adt.Array, error) {
return v0adt.AsArray(s.store, s.Sectors)
}
func (s *v0State) decodeSectorOnChainInfo(val *cbg.Deferred) (SectorOnChainInfo, error) {
var si v0miner.SectorOnChainInfo
err := si.UnmarshalCBOR(bytes.NewReader(val.Raw))
return si, err
}
func (s *v0State) precommits() (adt.Map, error) {
return v0adt.AsMap(s.store, s.PreCommittedSectors)
}
func (s *v0State) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) {
var sp v0miner.SectorPreCommitOnChainInfo
err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw))
return sp, err
}
func (d *v0Deadline) LoadPartition(idx uint64) (Partition, error) { func (d *v0Deadline) LoadPartition(idx uint64) (Partition, error) {
p, err := d.Deadline.LoadPartition(d.store, idx) p, err := d.Deadline.LoadPartition(d.store, idx)
if err != nil { if err != nil {
@ -263,6 +294,16 @@ func (d *v0Deadline) ForEachPartition(cb func(uint64, Partition) error) error {
}) })
} }
func (s *v0Deadline) PartitionsChanged(other Deadline) bool {
v0other, ok := other.(*v0Deadline)
if !ok {
// treat an upgrade as a change, always
return true
}
return s.Deadline.Partitions.Equals(v0other.Deadline.Partitions)
}
func (d *v0Deadline) PostSubmissions() (bitfield.BitField, error) { func (d *v0Deadline) PostSubmissions() (bitfield.BitField, error) {
return d.Deadline.PostSubmissions, nil return d.Deadline.PostSubmissions, nil
} }

View File

@ -4,8 +4,6 @@ import (
"bytes" "bytes"
"context" "context"
v0miner "github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
@ -325,83 +323,12 @@ func (sp *StatePredicates) OnMinerActorChange(minerAddr address.Address, diffMin
}) })
} }
type MinerSectorChanges struct {
Added []miner.SectorOnChainInfo
Extended []SectorExtensions
Removed []miner.SectorOnChainInfo
}
var _ adt.AdtArrayDiff = &MinerSectorChanges{}
type SectorExtensions struct {
From miner.SectorOnChainInfo
To miner.SectorOnChainInfo
}
func (m *MinerSectorChanges) Add(key uint64, val *typegen.Deferred) error {
si := new(miner.SectorOnChainInfo)
err := si.UnmarshalCBOR(bytes.NewReader(val.Raw))
if err != nil {
return err
}
m.Added = append(m.Added, *si)
return nil
}
func (m *MinerSectorChanges) Modify(key uint64, from, to *typegen.Deferred) error {
siFrom := new(miner.SectorOnChainInfo)
err := siFrom.UnmarshalCBOR(bytes.NewReader(from.Raw))
if err != nil {
return err
}
siTo := new(miner.SectorOnChainInfo)
err = siTo.UnmarshalCBOR(bytes.NewReader(to.Raw))
if err != nil {
return err
}
if siFrom.Expiration != siTo.Expiration {
m.Extended = append(m.Extended, SectorExtensions{
From: *siFrom,
To: *siTo,
})
}
return nil
}
func (m *MinerSectorChanges) Remove(key uint64, val *typegen.Deferred) error {
si := new(miner.SectorOnChainInfo)
err := si.UnmarshalCBOR(bytes.NewReader(val.Raw))
if err != nil {
return err
}
m.Removed = append(m.Removed, *si)
return nil
}
func (sp *StatePredicates) OnMinerSectorChange() DiffMinerActorStateFunc { func (sp *StatePredicates) OnMinerSectorChange() DiffMinerActorStateFunc {
return func(ctx context.Context, oldState, newState miner.State) (changed bool, user UserData, err error) { return func(ctx context.Context, oldState, newState miner.State) (changed bool, user UserData, err error) {
sectorChanges := &MinerSectorChanges{ sectorChanges, err := miner.DiffSectors(oldState, newState)
Added: []miner.SectorOnChainInfo{},
Extended: []SectorExtensions{},
Removed: []miner.SectorOnChainInfo{},
}
oldSectors, err := oldState.LoadSectorsFromSet(nil, false)
if err != nil { if err != nil {
return false, nil, err return false, nil, err
} }
newSectors, err := newState.LoadSectorsFromSet(nil, false)
if err != nil {
return false, nil, err
}
if err := adt.DiffAdtArray(oldSectors, newSectors, sectorChanges); err != nil {
return false, nil, err
}
// nothing changed // nothing changed
if len(sectorChanges.Added)+len(sectorChanges.Extended)+len(sectorChanges.Removed) == 0 { if len(sectorChanges.Added)+len(sectorChanges.Extended)+len(sectorChanges.Removed) == 0 {
return false, nil, nil return false, nil, nil
@ -411,64 +338,13 @@ func (sp *StatePredicates) OnMinerSectorChange() DiffMinerActorStateFunc {
} }
} }
type MinerPreCommitChanges struct {
Added []miner.SectorPreCommitOnChainInfo
Removed []miner.SectorPreCommitOnChainInfo
}
func (m *MinerPreCommitChanges) AsKey(key string) (abi.Keyer, error) {
sector, err := abi.ParseUIntKey(key)
if err != nil {
return nil, err
}
return v0miner.SectorKey(abi.SectorNumber(sector)), nil
}
func (m *MinerPreCommitChanges) Add(key string, val *typegen.Deferred) error {
sp := new(miner.SectorPreCommitOnChainInfo)
err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw))
if err != nil {
return err
}
m.Added = append(m.Added, *sp)
return nil
}
func (m *MinerPreCommitChanges) Modify(key string, from, to *typegen.Deferred) error {
return nil
}
func (m *MinerPreCommitChanges) Remove(key string, val *typegen.Deferred) error {
sp := new(miner.SectorPreCommitOnChainInfo)
err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw))
if err != nil {
return err
}
m.Removed = append(m.Removed, *sp)
return nil
}
func (sp *StatePredicates) OnMinerPreCommitChange() DiffMinerActorStateFunc { func (sp *StatePredicates) OnMinerPreCommitChange() DiffMinerActorStateFunc {
return func(ctx context.Context, oldState, newState miner.State) (changed bool, user UserData, err error) { return func(ctx context.Context, oldState, newState miner.State) (changed bool, user UserData, err error) {
precommitChanges := &MinerPreCommitChanges{ precommitChanges, err := miner.DiffPreCommits(oldState, newState)
Added: []miner.SectorPreCommitOnChainInfo{},
Removed: []miner.SectorPreCommitOnChainInfo{},
}
oldPrecommits, err := oldState.LoadPreCommittedSectors()
if err != nil { if err != nil {
return false, nil, err return false, nil, err
} }
newPrecommits, err := newState.LoadPreCommittedSectors()
if err != nil {
return false, nil, err
}
if err := adt.DiffAdtMap(oldPrecommits, newPrecommits, precommitChanges); err != nil {
return false, nil, err
}
if len(precommitChanges.Added)+len(precommitChanges.Removed) == 0 { if len(precommitChanges.Added)+len(precommitChanges.Removed) == 0 {
return false, nil, nil return false, nil, nil
} }

View File

@ -409,7 +409,7 @@ func TestMinerSectorChange(t *testing.T) {
require.True(t, change) require.True(t, change)
require.NotNil(t, val) require.NotNil(t, val)
sectorChanges, ok := val.(*MinerSectorChanges) sectorChanges, ok := val.(*miner.SectorChanges)
require.True(t, ok) require.True(t, ok)
require.Equal(t, len(sectorChanges.Added), 1) require.Equal(t, len(sectorChanges.Added), 1)
@ -433,7 +433,7 @@ func TestMinerSectorChange(t *testing.T) {
require.True(t, change) require.True(t, change)
require.NotNil(t, val) require.NotNil(t, val)
sectorChanges, ok = val.(*MinerSectorChanges) sectorChanges, ok = val.(*miner.SectorChanges)
require.True(t, ok) require.True(t, ok)
require.Equal(t, 1, len(sectorChanges.Added)) require.Equal(t, 1, len(sectorChanges.Added))

View File

@ -16,12 +16,14 @@ import (
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/builtin/power"
"github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/apibstore"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/events/state" "github.com/filecoin-project/lotus/chain/events/state"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
cw_util "github.com/filecoin-project/lotus/cmd/lotus-chainwatch/util" cw_util "github.com/filecoin-project/lotus/cmd/lotus-chainwatch/util"
) )
@ -204,6 +206,8 @@ func (p *Processor) processMiners(ctx context.Context, minerTips map[types.TipSe
log.Debugw("Processed Miners", "duration", time.Since(start).String()) log.Debugw("Processed Miners", "duration", time.Since(start).String())
}() }()
stor := store.ActorStore(ctx, apibstore.NewAPIBlockstore(p.node))
var out []minerActorInfo var out []minerActorInfo
// TODO add parallel calls if this becomes slow // TODO add parallel calls if this becomes slow
for tipset, miners := range minerTips { for tipset, miners := range minerTips {
@ -230,15 +234,13 @@ func (p *Processor) processMiners(ctx context.Context, minerTips map[types.TipSe
mi.rawPower = claim.RawBytePower mi.rawPower = claim.RawBytePower
} }
// Get the miner state info // Get the miner state
astb, err := p.node.ChainReadObj(ctx, act.act.Head) mas, err := miner.Load(stor, &act.act)
if err != nil { if err != nil {
log.Warnw("failed to find miner actor state", "address", act.addr, "error", err) log.Warnw("failed to find miner actor state", "address", act.addr, "error", err)
continue continue
} }
if err := mi.state.UnmarshalCBOR(bytes.NewReader(astb)); err != nil { mi.state = mas
return nil, err
}
out = append(out, mi) out = append(out, mi)
} }
} }
@ -322,11 +324,6 @@ func (p *Processor) storeMinerPreCommitInfo(ctx context.Context, miners []minerA
for _, m := range miners { for _, m := range miners {
m := m m := m
grp.Go(func() error { grp.Go(func() error {
minerSectors, err := adt.AsArray(p.ctxStore, m.state.Sectors)
if err != nil {
return err
}
changes, err := p.getMinerPreCommitChanges(ctx, m) changes, err := p.getMinerPreCommitChanges(ctx, m)
if err != nil { if err != nil {
if strings.Contains(err.Error(), types.ErrActorNotFound.Error()) { if strings.Contains(err.Error(), types.ErrActorNotFound.Error()) {
@ -399,10 +396,12 @@ func (p *Processor) storeMinerPreCommitInfo(ctx context.Context, miners []minerA
} }
var preCommitExpired []uint64 var preCommitExpired []uint64
for _, removed := range changes.Removed { for _, removed := range changes.Removed {
var sector miner.SectorOnChainInfo // TODO: we can optimize this to not load the AMT every time, if necessary.
if found, err := minerSectors.Get(uint64(removed.Info.SectorNumber), &sector); err != nil { si, err := m.state.GetSector(removed.Info.SectorNumber)
if err != nil {
return err return err
} else if !found { }
if si == nil {
preCommitExpired = append(preCommitExpired, uint64(removed.Info.SectorNumber)) preCommitExpired = append(preCommitExpired, uint64(removed.Info.SectorNumber))
} }
} }
@ -653,21 +652,12 @@ func (p *Processor) storeMinerSectorEvents(ctx context.Context, sectorEvents, pr
func (p *Processor) getMinerStateAt(ctx context.Context, maddr address.Address, tskey types.TipSetKey) (miner.State, error) { func (p *Processor) getMinerStateAt(ctx context.Context, maddr address.Address, tskey types.TipSetKey) (miner.State, error) {
prevActor, err := p.node.StateGetActor(ctx, maddr, tskey) prevActor, err := p.node.StateGetActor(ctx, maddr, tskey)
if err != nil { if err != nil {
return miner.State{}, err return nil, err
} }
var out miner.State return miner.Load(store.ActorStore(ctx, apibstore.NewAPIBlockstore(p.node)), prevActor)
// Get the miner state info
astb, err := p.node.ChainReadObj(ctx, prevActor.Head)
if err != nil {
return miner.State{}, err
}
if err := out.UnmarshalCBOR(bytes.NewReader(astb)); err != nil {
return miner.State{}, err
}
return out, nil
} }
func (p *Processor) getMinerPreCommitChanges(ctx context.Context, m minerActorInfo) (*state.MinerPreCommitChanges, error) { func (p *Processor) getMinerPreCommitChanges(ctx context.Context, m minerActorInfo) (*miner.PreCommitChanges, error) {
pred := state.NewStatePredicates(p.node) pred := state.NewStatePredicates(p.node)
changed, val, err := pred.OnMinerActorChange(m.common.addr, pred.OnMinerPreCommitChange())(ctx, m.common.parentTsKey, m.common.tsKey) changed, val, err := pred.OnMinerActorChange(m.common.addr, pred.OnMinerPreCommitChange())(ctx, m.common.parentTsKey, m.common.tsKey)
if err != nil { if err != nil {
@ -676,11 +666,11 @@ func (p *Processor) getMinerPreCommitChanges(ctx context.Context, m minerActorIn
if !changed { if !changed {
return nil, nil return nil, nil
} }
out := val.(*state.MinerPreCommitChanges) out := val.(*miner.PreCommitChanges)
return out, nil return out, nil
} }
func (p *Processor) getMinerSectorChanges(ctx context.Context, m minerActorInfo) (*state.MinerSectorChanges, error) { func (p *Processor) getMinerSectorChanges(ctx context.Context, m minerActorInfo) (*miner.SectorChanges, error) {
pred := state.NewStatePredicates(p.node) pred := state.NewStatePredicates(p.node)
changed, val, err := pred.OnMinerActorChange(m.common.addr, pred.OnMinerSectorChange())(ctx, m.common.parentTsKey, m.common.tsKey) changed, val, err := pred.OnMinerActorChange(m.common.addr, pred.OnMinerSectorChange())(ctx, m.common.parentTsKey, m.common.tsKey)
if err != nil { if err != nil {
@ -689,7 +679,7 @@ func (p *Processor) getMinerSectorChanges(ctx context.Context, m minerActorInfo)
if !changed { if !changed {
return nil, nil return nil, nil
} }
out := val.(*state.MinerSectorChanges) out := val.(*miner.SectorChanges)
return out, nil return out, nil
} }
@ -698,8 +688,20 @@ func (p *Processor) diffMinerPartitions(ctx context.Context, m minerActorInfo, e
if err != nil { if err != nil {
return err return err
} }
dlIdx := prevMiner.CurrentDeadline
curMiner := m.state curMiner := m.state
if !prevMiner.DeadlinesChanged(curMiner) {
return nil
}
panic("TODO")
// FIXME: This code doesn't work.
// 1. We need to diff all deadlines, not just the "current" deadline.
// 2. We need to handle the case where we _add_ a partition. (i.e.,
// where len(newPartitions) != len(oldPartitions).
/*
// NOTE: If we change the number of deadlines in an upgrade, this will
// break.
// load the old deadline // load the old deadline
prevDls, err := prevMiner.LoadDeadlines(p.ctxStore) prevDls, err := prevMiner.LoadDeadlines(p.ctxStore)
@ -803,74 +805,79 @@ func (p *Processor) diffMinerPartitions(ctx context.Context, m minerActorInfo, e
} }
return nil return nil
*/
} }
func (p *Processor) diffPartition(prevPart, curPart miner.Partition) (*PartitionStatus, error) { func (p *Processor) diffPartition(prevPart, curPart miner.Partition) (*PartitionStatus, error) {
// all the sectors that were in previous but not in current prevLiveSectors, err := prevPart.LiveSectors()
allRemovedSectors, err := bitfield.SubtractBitField(prevPart.Sectors, curPart.Sectors) if err != nil {
return nil, err
}
curLiveSectors, err := curPart.LiveSectors()
if err != nil { if err != nil {
return nil, err return nil, err
} }
// list of sectors that were terminated before their expiration. removedSectors, err := bitfield.SubtractBitField(prevLiveSectors, curLiveSectors)
terminatedEarlyArr, err := adt.AsArray(p.ctxStore, curPart.EarlyTerminated)
if err != nil { if err != nil {
return nil, err return nil, err
} }
expired := bitfield.New() prevRecoveries, err := prevPart.RecoveringSectors()
var bf bitfield.BitField
if err := terminatedEarlyArr.ForEach(&bf, func(i int64) error {
// expired = all removals - termination
expirations, err := bitfield.SubtractBitField(allRemovedSectors, bf)
if err != nil {
return err
}
// merge with expired sectors from other epochs
expired, err = bitfield.MergeBitFields(expirations, expired)
if err != nil {
return nil
}
return nil
}); err != nil {
return nil, err
}
// terminated = all removals - expired
terminated, err := bitfield.SubtractBitField(allRemovedSectors, expired)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// faults in current but not previous curRecoveries, err := curPart.RecoveringSectors()
faults, err := bitfield.SubtractBitField(curPart.Recoveries, prevPart.Recoveries)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// recoveries in current but not previous newRecoveries, err := bitfield.SubtractBitField(curRecoveries, prevRecoveries)
inRecovery, err := bitfield.SubtractBitField(curPart.Recoveries, prevPart.Recoveries) if err != nil {
return nil, err
}
prevFaults, err := prevPart.FaultySectors()
if err != nil {
return nil, err
}
curFaults, err := curPart.FaultySectors()
if err != nil {
return nil, err
}
newFaults, err := bitfield.SubtractBitField(curFaults, prevFaults)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// all current good sectors // all current good sectors
newActiveSectors, err := curPart.ActiveSectors() curActiveSectors, err := curPart.ActiveSectors()
if err != nil { if err != nil {
return nil, err return nil, err
} }
// sectors that were previously fault and are now currently active are considered recovered. // sectors that were previously fault and are now currently active are considered recovered.
recovered, err := bitfield.IntersectBitField(prevPart.Faults, newActiveSectors) recovered, err := bitfield.IntersectBitField(prevFaults, curActiveSectors)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// TODO: distinguish between "terminated" and "expired" sectors. The
// previous code here never had a chance of working in the first place,
// so I'm not going to try to replicate it right now.
//
// How? If the sector expires before it should (according to sector
// info) and it wasn't replaced by a pre-commit deleted in this change
// set, it was "early terminated".
return &PartitionStatus{ return &PartitionStatus{
Terminated: terminated, Terminated: bitfield.New(),
Expired: expired, Expired: removedSectors,
Faulted: faults, Faulted: newFaults,
InRecovery: inRecovery, InRecovery: newRecoveries,
Recovered: recovered, Recovered: recovered,
}, nil }, nil
} }