Merge pull request #2618 from filecoin-project/asr/has-power
Use specs actor's MinerNominalPowerMeetsConsensusMinimum
This commit is contained in:
commit
2bc1a7e327
@ -641,6 +641,7 @@ type MiningBaseInfo struct {
|
|||||||
SectorSize abi.SectorSize
|
SectorSize abi.SectorSize
|
||||||
PrevBeaconEntry types.BeaconEntry
|
PrevBeaconEntry types.BeaconEntry
|
||||||
BeaconEntries []types.BeaconEntry
|
BeaconEntries []types.BeaconEntry
|
||||||
|
HasMinPower bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type BlockTemplate struct {
|
type BlockTemplate struct {
|
||||||
|
@ -567,6 +567,11 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe
|
|||||||
return nil, xerrors.Errorf("resolving worker address: %w", err)
|
return nil, xerrors.Errorf("resolving worker address: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hmp, err := MinerHasMinPower(ctx, sm, maddr, lbts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("determining if miner has min power failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return &api.MiningBaseInfo{
|
return &api.MiningBaseInfo{
|
||||||
MinerPower: mpow.QualityAdjPower,
|
MinerPower: mpow.QualityAdjPower,
|
||||||
NetworkPower: tpow.QualityAdjPower,
|
NetworkPower: tpow.QualityAdjPower,
|
||||||
@ -575,6 +580,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe
|
|||||||
SectorSize: info.SectorSize,
|
SectorSize: info.SectorSize,
|
||||||
PrevBeaconEntry: *prev,
|
PrevBeaconEntry: *prev,
|
||||||
BeaconEntries: entries,
|
BeaconEntries: entries,
|
||||||
|
HasMinPower: hmp,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,3 +665,13 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me
|
|||||||
m := MethodsMap[act.Code][method]
|
m := MethodsMap[act.Code][method]
|
||||||
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) {
|
||||||
|
var ps power.State
|
||||||
|
_, err := sm.LoadActorState(ctx, builtin.StoragePowerActorAddr, &ps, ts)
|
||||||
|
if err != nil {
|
||||||
|
return false, xerrors.Errorf("loading power actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps.MinerNominalPowerMeetsConsensusMinimum(sm.ChainStore().Store(ctx), addr)
|
||||||
|
}
|
||||||
|
@ -191,14 +191,14 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
|
|||||||
// if we can't find it, we check whether we are (near) synced in the chain.
|
// if we can't find it, we check whether we are (near) synced in the chain.
|
||||||
// if we are not synced we cannot validate the block and we must ignore it.
|
// if we are not synced we cannot validate the block and we must ignore it.
|
||||||
// if we are synced and the miner is unknown, then the block is rejcected.
|
// if we are synced and the miner is unknown, then the block is rejcected.
|
||||||
key, err := bv.getMinerWorkerKey(ctx, blk)
|
key, err := bv.checkPowerAndGetWorkerKey(ctx, blk.Header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if bv.isChainNearSynced() {
|
if bv.isChainNearSynced() {
|
||||||
log.Warnf("received block message from unknown miner over pubsub; rejecting message")
|
log.Warnf("received block from unknown miner or miner that doesn't meet min power over pubsub; rejecting message")
|
||||||
recordFailure("unknown_miner")
|
recordFailure("unknown_miner")
|
||||||
return pubsub.ValidationReject
|
return pubsub.ValidationReject
|
||||||
} else {
|
} else {
|
||||||
log.Warnf("cannot validate block message; unknown miner in unsynced chain")
|
log.Warnf("cannot validate block message; unknown miner or miner that doesn't meet min power in unsynced chain")
|
||||||
return pubsub.ValidationIgnore
|
return pubsub.ValidationIgnore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -283,60 +283,83 @@ func (bv *BlockValidator) validateMsgMeta(ctx context.Context, msg *types.BlockM
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bv *BlockValidator) getMinerWorkerKey(ctx context.Context, msg *types.BlockMsg) (address.Address, error) {
|
func (bv *BlockValidator) checkPowerAndGetWorkerKey(ctx context.Context, bh *types.BlockHeader) (address.Address, error) {
|
||||||
addr := msg.Header.Miner
|
addr := bh.Miner
|
||||||
|
|
||||||
bv.mx.Lock()
|
bv.mx.Lock()
|
||||||
key, ok := bv.keycache[addr.String()]
|
key, ok := bv.keycache[addr.String()]
|
||||||
bv.mx.Unlock()
|
bv.mx.Unlock()
|
||||||
if ok {
|
if !ok {
|
||||||
return key, nil
|
// TODO I have a feeling all this can be simplified by cleverer DI to use the API
|
||||||
|
ts := bv.chain.GetHeaviestTipSet()
|
||||||
|
st, _, err := bv.stmgr.TipSetState(ctx, ts)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
buf := bufbstore.NewBufferedBstore(bv.chain.Blockstore())
|
||||||
|
cst := cbor.NewCborStore(buf)
|
||||||
|
state, err := state.LoadStateTree(cst, st)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
act, err := state.GetActor(addr)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
blk, err := bv.chain.Blockstore().Get(act.Head)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
aso := blk.RawData()
|
||||||
|
|
||||||
|
var mst miner.State
|
||||||
|
err = mst.UnmarshalCBOR(bytes.NewReader(aso))
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := mst.GetInfo(adt.WrapStore(ctx, cst))
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
worker := info.Worker
|
||||||
|
key, err = bv.stmgr.ResolveToKeyAddress(ctx, worker, ts)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bv.mx.Lock()
|
||||||
|
bv.keycache[addr.String()] = key
|
||||||
|
bv.mx.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO I have a feeling all this can be simplified by cleverer DI to use the API
|
// we check that the miner met the minimum power at the lookback tipset
|
||||||
ts := bv.chain.GetHeaviestTipSet()
|
|
||||||
st, _, err := bv.stmgr.TipSetState(ctx, ts)
|
baseTs, err := bv.stmgr.ChainStore().LoadTipSet(types.NewTipSetKey(bh.Parents...))
|
||||||
if err != nil {
|
|
||||||
return address.Undef, err
|
|
||||||
}
|
|
||||||
buf := bufbstore.NewBufferedBstore(bv.chain.Blockstore())
|
|
||||||
cst := cbor.NewCborStore(buf)
|
|
||||||
state, err := state.LoadStateTree(cst, st)
|
|
||||||
if err != nil {
|
|
||||||
return address.Undef, err
|
|
||||||
}
|
|
||||||
act, err := state.GetActor(addr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Warnf("failed to load parent tipset of incoming block")
|
||||||
return address.Undef, err
|
return address.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
blk, err := bv.chain.Blockstore().Get(act.Head)
|
lbts, err := stmgr.GetLookbackTipSetForRound(ctx, bv.stmgr, baseTs, bh.Height)
|
||||||
if err != nil {
|
|
||||||
return address.Undef, err
|
|
||||||
}
|
|
||||||
aso := blk.RawData()
|
|
||||||
|
|
||||||
var mst miner.State
|
|
||||||
err = mst.UnmarshalCBOR(bytes.NewReader(aso))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Warnf("failed to load lookback tipset for incoming block")
|
||||||
return address.Undef, err
|
return address.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := mst.GetInfo(adt.WrapStore(ctx, cst))
|
hmp, err := stmgr.MinerHasMinPower(ctx, bv.stmgr, bh.Miner, lbts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Warnf("failed to determine if incoming block's miner has minimum power")
|
||||||
return address.Undef, err
|
return address.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
worker := info.Worker
|
if !hmp {
|
||||||
key, err = bv.stmgr.ResolveToKeyAddress(ctx, worker, ts)
|
log.Warnf("incoming block's miner does not have minimum power")
|
||||||
if err != nil {
|
return address.Undef, xerrors.New("incoming block's miner does not have minimum power")
|
||||||
return address.Undef, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bv.mx.Lock()
|
|
||||||
bv.keycache[addr.String()] = key
|
|
||||||
bv.mx.Unlock()
|
|
||||||
|
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,6 +739,15 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
|
|||||||
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)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("determining if miner has min power failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hp {
|
||||||
|
return xerrors.New("block's miner does not meet minimum power threshold")
|
||||||
|
}
|
||||||
|
|
||||||
rBeacon := *prevBeacon
|
rBeacon := *prevBeacon
|
||||||
if len(h.BeaconEntries) != 0 {
|
if len(h.BeaconEntries) != 0 {
|
||||||
rBeacon = h.BeaconEntries[len(h.BeaconEntries)-1]
|
rBeacon = h.BeaconEntries[len(h.BeaconEntries)-1]
|
||||||
|
@ -14,7 +14,6 @@ import (
|
|||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
@ -269,15 +268,6 @@ func (m *Miner) GetBestMiningCandidate(ctx context.Context) (*MiningBase, error)
|
|||||||
return m.lastWork, nil
|
return m.lastWork, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Miner) hasPower(ctx context.Context, addr address.Address, ts *types.TipSet) (bool, error) {
|
|
||||||
mpower, err := m.api.StateMinerPower(ctx, addr, ts.Key())
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return mpower.MinerPower.QualityAdjPower.GreaterThanEqual(power.ConsensusMinerMinPower), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// mineOne attempts to mine a single block, and does so synchronously, if and
|
// mineOne attempts to mine a single block, and does so synchronously, if and
|
||||||
// only if we are eligible to mine.
|
// only if we are eligible to mine.
|
||||||
//
|
//
|
||||||
@ -301,6 +291,10 @@ 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 {
|
||||||
|
// slashed or just have no power yet
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
tMBI := build.Clock.Now()
|
tMBI := build.Clock.Now()
|
||||||
|
|
||||||
@ -309,15 +303,6 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*types.BlockMsg,
|
|||||||
tDrand := build.Clock.Now()
|
tDrand := build.Clock.Now()
|
||||||
bvals := mbi.BeaconEntries
|
bvals := mbi.BeaconEntries
|
||||||
|
|
||||||
hasPower, err := m.hasPower(ctx, m.address, base.TipSet)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("checking if miner is slashed: %w", err)
|
|
||||||
}
|
|
||||||
if !hasPower {
|
|
||||||
// slashed or just have no power yet
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
tPowercheck := build.Clock.Now()
|
tPowercheck := build.Clock.Now()
|
||||||
|
|
||||||
log.Infof("Time delta between now and our mining base: %ds (nulls: %d)", uint64(build.Clock.Now().Unix())-base.TipSet.MinTimestamp(), base.NullRounds)
|
log.Infof("Time delta between now and our mining base: %ds (nulls: %d)", uint64(build.Clock.Now().Unix())-base.TipSet.MinTimestamp(), base.NullRounds)
|
||||||
|
Loading…
Reference in New Issue
Block a user