Merge pull request #4188 from filecoin-project/asr/miner-eligible

Update miner eligibility checks for v2 actors
This commit is contained in:
Aayush Rajasekaran 2020-10-06 17:38:46 -04:00 committed by GitHub
commit 9857e42206
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 116 additions and 28 deletions

View File

@ -806,14 +806,14 @@ type CirculatingSupply struct {
} }
type MiningBaseInfo struct { type MiningBaseInfo struct {
MinerPower types.BigInt MinerPower types.BigInt
NetworkPower types.BigInt NetworkPower types.BigInt
Sectors []builtin.SectorInfo Sectors []builtin.SectorInfo
WorkerKey address.Address WorkerKey address.Address
SectorSize abi.SectorSize SectorSize abi.SectorSize
PrevBeaconEntry types.BeaconEntry PrevBeaconEntry types.BeaconEntry
BeaconEntries []types.BeaconEntry BeaconEntries []types.BeaconEntry
HasMinPower bool EligibleForMining bool
} }
type BlockTemplate struct { type BlockTemplate struct {

View File

@ -58,6 +58,7 @@ type State interface {
VestedFunds(abi.ChainEpoch) (abi.TokenAmount, error) VestedFunds(abi.ChainEpoch) (abi.TokenAmount, error)
// Funds locked for various reasons. // Funds locked for various reasons.
LockedFunds() (LockedFunds, error) LockedFunds() (LockedFunds, error)
FeeDebt() (abi.TokenAmount, error)
GetSector(abi.SectorNumber) (*SectorOnChainInfo, error) GetSector(abi.SectorNumber) (*SectorOnChainInfo, error)
FindSector(abi.SectorNumber) (*SectorLocation, error) FindSector(abi.SectorNumber) (*SectorLocation, error)
@ -144,6 +145,7 @@ type MinerInfo struct {
SealProofType abi.RegisteredSealProof SealProofType abi.RegisteredSealProof
SectorSize abi.SectorSize SectorSize abi.SectorSize
WindowPoStPartitionSectors uint64 WindowPoStPartitionSectors uint64
ConsensusFaultElapsed abi.ChainEpoch
} }
type SectorExpiration struct { type SectorExpiration struct {

View File

@ -4,6 +4,8 @@ import (
"bytes" "bytes"
"errors" "errors"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-bitfield"
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
@ -61,6 +63,10 @@ func (s *state0) LockedFunds() (LockedFunds, error) {
}, nil }, nil
} }
func (s *state0) FeeDebt() (abi.TokenAmount, error) {
return big.Zero(), nil
}
func (s *state0) InitialPledge() (abi.TokenAmount, error) { func (s *state0) InitialPledge() (abi.TokenAmount, error) {
return s.State.InitialPledgeRequirement, nil return s.State.InitialPledgeRequirement, nil
} }
@ -287,6 +293,7 @@ func (s *state0) Info() (MinerInfo, error) {
SealProofType: info.SealProofType, SealProofType: info.SealProofType,
SectorSize: info.SectorSize, SectorSize: info.SectorSize,
WindowPoStPartitionSectors: info.WindowPoStPartitionSectors, WindowPoStPartitionSectors: info.WindowPoStPartitionSectors,
ConsensusFaultElapsed: -1,
} }
if info.PendingWorkerKey != nil { if info.PendingWorkerKey != nil {

View File

@ -61,6 +61,10 @@ func (s *state2) LockedFunds() (LockedFunds, error) {
}, nil }, nil
} }
func (s *state2) FeeDebt() (abi.TokenAmount, error) {
return s.State.FeeDebt, nil
}
func (s *state2) InitialPledge() (abi.TokenAmount, error) { func (s *state2) InitialPledge() (abi.TokenAmount, error) {
return s.State.InitialPledge, nil return s.State.InitialPledge, nil
} }
@ -288,6 +292,7 @@ func (s *state2) Info() (MinerInfo, error) {
SealProofType: info.SealProofType, SealProofType: info.SealProofType,
SectorSize: info.SectorSize, SectorSize: info.SectorSize,
WindowPoStPartitionSectors: info.WindowPoStPartitionSectors, WindowPoStPartitionSectors: info.WindowPoStPartitionSectors,
ConsensusFaultElapsed: info.ConsensusFaultElapsed,
} }
if info.PendingWorkerKey != nil { if info.PendingWorkerKey != nil {

View File

@ -4,7 +4,6 @@ import (
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" market0 "github.com/filecoin-project/specs-actors/actors/builtin/market"
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"

View File

@ -9,6 +9,10 @@ import (
"runtime" "runtime"
"strings" "strings"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/network"
cid "github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors" "golang.org/x/xerrors"
@ -490,7 +494,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule
return nil, nil return nil, nil
} }
mpow, tpow, hmp, err := GetPowerRaw(ctx, sm, lbst, maddr) mpow, tpow, _, err := GetPowerRaw(ctx, sm, lbst, maddr)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to get power: %w", err) return nil, xerrors.Errorf("failed to get power: %w", err)
} }
@ -505,15 +509,21 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule
return nil, xerrors.Errorf("resolving worker address: %w", err) return nil, xerrors.Errorf("resolving worker address: %w", err)
} }
// TODO: Not ideal performance...This method reloads miner and power state (already looked up here and in GetPowerRaw)
eligible, err := MinerEligibleToMine(ctx, sm, maddr, ts, lbts)
if err != nil {
return nil, xerrors.Errorf("determining miner eligibility: %w", err)
}
return &api.MiningBaseInfo{ return &api.MiningBaseInfo{
MinerPower: mpow.QualityAdjPower, MinerPower: mpow.QualityAdjPower,
NetworkPower: tpow.QualityAdjPower, NetworkPower: tpow.QualityAdjPower,
Sectors: sectors, Sectors: sectors,
WorkerKey: worker, WorkerKey: worker,
SectorSize: info.SectorSize, SectorSize: info.SectorSize,
PrevBeaconEntry: *prev, PrevBeaconEntry: *prev,
BeaconEntries: entries, BeaconEntries: entries,
HasMinPower: hmp, EligibleForMining: eligible,
}, nil }, nil
} }
@ -595,7 +605,7 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
} }
func MinerHasMinPower(ctx context.Context, sm *StateManager, addr address.Address, ts *types.TipSet) (bool, error) { func minerHasMinPower(ctx context.Context, sm *StateManager, addr address.Address, ts *types.TipSet) (bool, error) {
pact, err := sm.LoadActor(ctx, power.Address, ts) pact, err := sm.LoadActor(ctx, power.Address, ts)
if err != nil { if err != nil {
return false, xerrors.Errorf("loading power actor state: %w", err) return false, xerrors.Errorf("loading power actor state: %w", err)
@ -609,6 +619,70 @@ func MinerHasMinPower(ctx context.Context, sm *StateManager, addr address.Addres
return ps.MinerNominalPowerMeetsConsensusMinimum(addr) return ps.MinerNominalPowerMeetsConsensusMinimum(addr)
} }
func MinerEligibleToMine(ctx context.Context, sm *StateManager, addr address.Address, baseTs *types.TipSet, lookbackTs *types.TipSet) (bool, error) {
hmp, err := minerHasMinPower(ctx, sm, addr, lookbackTs)
// TODO: We're blurring the lines between a "runtime network version" and a "Lotus upgrade epoch", is that unavoidable?
if sm.GetNtwkVersion(ctx, baseTs.Height()) <= network.Version3 {
return hmp, err
}
if err != nil {
return false, err
}
if !hmp {
return false, nil
}
// Post actors v2, also check MinerEligibleForElection with base ts
pact, err := sm.LoadActor(ctx, power.Address, baseTs)
if err != nil {
return false, xerrors.Errorf("loading power actor state: %w", err)
}
pstate, err := power.Load(sm.cs.Store(ctx), pact)
if err != nil {
return false, err
}
mact, err := sm.LoadActor(ctx, addr, baseTs)
if err != nil {
return false, xerrors.Errorf("loading miner actor state: %w", err)
}
mstate, err := miner.Load(sm.cs.Store(ctx), mact)
if err != nil {
return false, err
}
// Non-empty power claim.
if claim, found, err := pstate.MinerPower(addr); err != nil {
return false, err
} else if !found {
return false, err
} else if claim.QualityAdjPower.LessThanEqual(big.Zero()) {
return false, err
}
// No fee debt.
if debt, err := mstate.FeeDebt(); err != nil {
return false, err
} else if !debt.IsZero() {
return false, err
}
// No active consensus faults.
if mInfo, err := mstate.Info(); err != nil {
return false, err
} else if baseTs.Height() <= mInfo.ConsensusFaultElapsed {
return false, nil
}
return true, nil
}
func CheckTotalFIL(ctx context.Context, sm *StateManager, ts *types.TipSet) (abi.TokenAmount, error) { func CheckTotalFIL(ctx context.Context, sm *StateManager, ts *types.TipSet) (abi.TokenAmount, error) {
str, err := state.LoadStateTree(sm.ChainStore().Store(ctx), ts.ParentState()) str, err := state.LoadStateTree(sm.ChainStore().Store(ctx), ts.ParentState())
if err != nil { if err != nil {

View File

@ -485,14 +485,14 @@ func (bv *BlockValidator) checkPowerAndGetWorkerKey(ctx context.Context, bh *typ
return address.Undef, ErrSoftFailure return address.Undef, ErrSoftFailure
} }
hmp, err := stmgr.MinerHasMinPower(ctx, bv.stmgr, bh.Miner, lbts) eligible, err := stmgr.MinerEligibleToMine(ctx, bv.stmgr, bh.Miner, baseTs, lbts)
if err != nil { if err != nil {
log.Warnf("failed to determine if incoming block's miner has minimum power: %s", err) log.Warnf("failed to determine if incoming block's miner has minimum power: %s", err)
return address.Undef, ErrSoftFailure return address.Undef, ErrSoftFailure
} }
if !hmp { if !eligible {
log.Warnf("incoming block's miner does not have minimum power") log.Warnf("incoming block's miner is ineligible")
return address.Undef, ErrInsufficientPower return address.Undef, ErrInsufficientPower
} }

View File

@ -827,13 +827,13 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock, use
return xerrors.Errorf("block is not claiming to be a winner") return xerrors.Errorf("block is not claiming to be a winner")
} }
hp, err := stmgr.MinerHasMinPower(ctx, syncer.sm, h.Miner, lbts) eligible, err := stmgr.MinerEligibleToMine(ctx, syncer.sm, h.Miner, baseTs, lbts)
if err != nil { if err != nil {
return xerrors.Errorf("determining if miner has min power failed: %w", err) return xerrors.Errorf("determining if miner has min power failed: %w", err)
} }
if !hp { if !eligible {
return xerrors.New("block's miner does not meet minimum power threshold") return xerrors.New("block's miner is ineligible to mine")
} }
rBeacon := *prevBeacon rBeacon := *prevBeacon

View File

@ -1611,7 +1611,7 @@ Response:
"Data": "Ynl0ZSBhcnJheQ==" "Data": "Ynl0ZSBhcnJheQ=="
}, },
"BeaconEntries": null, "BeaconEntries": null,
"HasMinPower": true "EligibleForMining": true
} }
``` ```
@ -3531,7 +3531,8 @@ Response:
"Multiaddrs": null, "Multiaddrs": null,
"SealProofType": 3, "SealProofType": 3,
"SectorSize": 34359738368, "SectorSize": 34359738368,
"WindowPoStPartitionSectors": 42 "WindowPoStPartitionSectors": 42,
"ConsensusFaultElapsed": 10101
} }
``` ```

View File

@ -362,7 +362,7 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*types.BlockMsg,
if mbi == nil { if mbi == nil {
return nil, nil return nil, nil
} }
if !mbi.HasMinPower { if !mbi.EligibleForMining {
// slashed or just have no power yet // slashed or just have no power yet
return nil, nil return nil, nil
} }