Merge pull request #4188 from filecoin-project/asr/miner-eligible
Update miner eligibility checks for v2 actors
This commit is contained in:
commit
9857e42206
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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"
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user