Merge pull request #1557 from filecoin-project/feat/power-table-lookback

Use lookback to get sector set and power for miners
This commit is contained in:
Łukasz Magiera 2020-04-18 01:53:54 +02:00 committed by GitHub
commit 9c5cda0efa
9 changed files with 93 additions and 57 deletions

View File

@ -71,7 +71,7 @@ type FullNode interface {
// miner
MinerGetBaseInfo(context.Context, address.Address, types.TipSetKey) (*MiningBaseInfo, error)
MinerGetBaseInfo(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*MiningBaseInfo, error)
MinerCreateBlock(context.Context, *BlockTemplate) (*types.BlockMsg, error)
// // UX ?
@ -382,7 +382,7 @@ type ComputeStateOutput struct {
type MiningBaseInfo struct {
MinerPower types.BigInt
NetworkPower types.BigInt
Sectors []*ChainSectorInfo
Sectors []abi.SectorInfo
WorkerKey address.Address
SectorSize abi.SectorSize
PrevBeaconEntry types.BeaconEntry

View File

@ -87,8 +87,8 @@ type FullNodeStruct struct {
MpoolGetNonce func(context.Context, address.Address) (uint64, error) `perm:"read"`
MpoolSub func(context.Context) (<-chan api.MpoolUpdate, error) `perm:"read"`
MinerGetBaseInfo func(context.Context, address.Address, types.TipSetKey) (*api.MiningBaseInfo, error) `perm:"read"`
MinerCreateBlock func(context.Context, *api.BlockTemplate) (*types.BlockMsg, error) `perm:"write"`
MinerGetBaseInfo func(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*api.MiningBaseInfo, error) `perm:"read"`
MinerCreateBlock func(context.Context, *api.BlockTemplate) (*types.BlockMsg, error) `perm:"write"`
WalletNew func(context.Context, crypto.SigType) (address.Address, error) `perm:"write"`
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
@ -332,8 +332,8 @@ func (c *FullNodeStruct) MpoolSub(ctx context.Context) (<-chan api.MpoolUpdate,
return c.Internal.MpoolSub(ctx)
}
func (c *FullNodeStruct) MinerGetBaseInfo(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
return c.Internal.MinerGetBaseInfo(ctx, maddr, tsk)
func (c *FullNodeStruct) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoch abi.ChainEpoch, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
return c.Internal.MinerGetBaseInfo(ctx, maddr, epoch, tsk)
}
func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, bt *api.BlockTemplate) (*types.BlockMsg, error) {

View File

@ -71,6 +71,8 @@ const MaxSealLookback = SealRandomnessLookbackLimit + 2000 // TODO: Get from spe
// Epochs
const TicketRandomnessLookback = 1
const WinningPoStSectorSetLookback = 10
// /////
// Devnet settings

View File

@ -277,9 +277,9 @@ func CarWalkFunc(nd format.Node) (out []*format.Link, err error) {
}
func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m address.Address, round abi.ChainEpoch) ([]types.BeaconEntry, *types.ElectionProof, *types.Ticket, error) {
mc := &mca{w: cg.w, sm: cg.sm}
mc := &mca{w: cg.w, sm: cg.sm, pv: ffiwrapper.ProofVerifier}
mbi, err := mc.MinerGetBaseInfo(ctx, m, pts.Key())
mbi, err := mc.MinerGetBaseInfo(ctx, m, round, pts.Key())
if err != nil {
return nil, nil, nil, xerrors.Errorf("get miner base info: %w", err)
}
@ -476,7 +476,7 @@ func (cg *ChainGen) YieldRepo() (repo.Repo, error) {
type MiningCheckAPI interface {
ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
MinerGetBaseInfo(context.Context, address.Address, types.TipSetKey) (*api.MiningBaseInfo, error)
MinerGetBaseInfo(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*api.MiningBaseInfo, error)
WalletSign(context.Context, address.Address, []byte) (*crypto.Signature, error)
}
@ -484,6 +484,7 @@ type MiningCheckAPI interface {
type mca struct {
w *wallet.Wallet
sm *stmgr.StateManager
pv ffiwrapper.Verifier
}
func (mca mca) ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
@ -495,8 +496,8 @@ func (mca mca) ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, pers
return mca.sm.ChainStore().GetRandomness(ctx, pts.Cids(), personalization, randEpoch, entropy)
}
func (mca mca) MinerGetBaseInfo(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
return stmgr.MinerGetBaseInfo(ctx, mca.sm, tsk, maddr)
func (mca mca) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoch abi.ChainEpoch, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
return stmgr.MinerGetBaseInfo(ctx, mca.sm, tsk, epoch, maddr, mca.pv)
}
func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*crypto.Signature, error) {

View File

@ -2,6 +2,7 @@ package stmgr
import (
"context"
amt "github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi"
@ -16,6 +17,7 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
@ -56,10 +58,10 @@ func GetMinerWorkerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr
}
func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (power.Claim, power.Claim, error) {
return getPowerRaw(ctx, sm, ts.ParentState(), maddr)
return GetPowerRaw(ctx, sm, ts.ParentState(), maddr)
}
func getPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (power.Claim, power.Claim, error) {
func GetPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (power.Claim, power.Claim, error) {
var ps power.State
_, err := sm.LoadActorStateRaw(ctx, builtin.StoragePowerActorAddr, &ps, st)
if err != nil {
@ -133,16 +135,11 @@ func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet,
return LoadSectorsFromSet(ctx, sm.ChainStore().Blockstore(), mas.Sectors, filter)
}
func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]abi.SectorInfo, error) {
pts, err := sm.cs.LoadTipSet(ts.Parents()) // TODO: Review: check correct lookback for winningPost sector set
if err != nil {
return nil, xerrors.Errorf("loading parent tipset: %w", err)
}
func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]abi.SectorInfo, error) {
var mas miner.State
_, err = sm.LoadActorStateRaw(ctx, maddr, &mas, pts.ParentState())
_, err := sm.LoadActorStateRaw(ctx, maddr, &mas, st)
if err != nil {
return nil, xerrors.Errorf("(get ssize) failed to load miner actor state: %w", err)
return nil, xerrors.Errorf("(get sectors) failed to load miner actor state: %w", err)
}
// TODO: Optimization: we could avoid loaditg the whole proving set here if we had AMT.GetNth with bitfield filtering
@ -166,12 +163,6 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S
return nil, xerrors.Errorf("getting miner ID: %w", err)
}
// TODO: use the right dst, also NB: not using any 'entropy' in this call because nicola really didnt want it
rand, err := sm.cs.GetRandomness(ctx, ts.Cids(), crypto.DomainSeparationTag_ElectionPoStChallengeSeed, ts.Height()-1, nil)
if err != nil {
return nil, xerrors.Errorf("failed to get randomness for winning post: %w", err)
}
ids, err := pv.GenerateWinningPoStSectorChallenge(ctx, wpt, abi.ActorID(mid), rand, uint64(len(sectorSet)))
if err != nil {
return nil, xerrors.Errorf("generating winning post challenges: %w", err)
@ -424,29 +415,58 @@ func GetProvingSetRaw(ctx context.Context, sm *StateManager, mas miner.State) ([
return provset, nil
}
func MinerGetBaseInfo(ctx context.Context, sm *StateManager, tsk types.TipSetKey, maddr address.Address) (*api.MiningBaseInfo, error) {
func GetLookbackTipSetForRound(ctx context.Context, sm *StateManager, ts *types.TipSet, round abi.ChainEpoch) (*types.TipSet, error) {
var lbr abi.ChainEpoch
if round > build.WinningPoStSectorSetLookback {
lbr = round - build.WinningPoStSectorSetLookback
}
// more null blocks than our lookback
if lbr > ts.Height() {
return ts, nil
}
lbts, err := sm.ChainStore().GetTipsetByHeight(ctx, lbr, ts)
if err != nil {
return nil, xerrors.Errorf("failed to get lookback tipset: %w", err)
}
return lbts, nil
}
func MinerGetBaseInfo(ctx context.Context, sm *StateManager, tsk types.TipSetKey, round abi.ChainEpoch, maddr address.Address, pv ffiwrapper.Verifier) (*api.MiningBaseInfo, error) {
ts, err := sm.ChainStore().LoadTipSet(tsk)
if err != nil {
return nil, xerrors.Errorf("failed to load tipset for mining base: %w", err)
}
st, _, err := sm.TipSetState(ctx, ts)
lbts, err := GetLookbackTipSetForRound(ctx, sm, ts, round)
if err != nil {
return nil, xerrors.Errorf("getting lookback miner actor state: %w", err)
}
lbst, _, err := sm.TipSetState(ctx, lbts)
if err != nil {
return nil, err
}
var mas miner.State
_, err = sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil {
return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
}
provset, err := GetProvingSetRaw(ctx, sm, mas)
if err != nil {
if _, err := sm.LoadActorStateRaw(ctx, maddr, &mas, lbst); err != nil {
return nil, err
}
mpow, tpow, err := getPowerRaw(ctx, sm, st, maddr)
// TODO: use the right dst, also NB: not using any 'entropy' in this call because nicola really didnt want it
prand, err := sm.cs.GetRandomness(ctx, ts.Cids(), crypto.DomainSeparationTag_ElectionPoStChallengeSeed, round-1, nil)
if err != nil {
return nil, xerrors.Errorf("failed to get randomness for winning post: %w", err)
}
sectors, err := GetSectorsForWinningPoSt(ctx, pv, sm, lbst, maddr, prand)
if err != nil {
return nil, xerrors.Errorf("getting wpost proving set: %w", err)
}
mpow, tpow, err := GetPowerRaw(ctx, sm, lbst, maddr)
if err != nil {
return nil, xerrors.Errorf("failed to get power: %w", err)
}
@ -464,7 +484,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, tsk types.TipSetKey
return &api.MiningBaseInfo{
MinerPower: mpow.QualityAdjPower,
NetworkPower: tpow.QualityAdjPower,
Sectors: provset,
Sectors: sectors,
WorkerKey: worker,
SectorSize: mas.Info.SectorSize,
PrevBeaconEntry: *prev,

View File

@ -942,6 +942,10 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h abi.ChainEpoch, t
return nil, xerrors.Errorf("looking for tipset with height less than start point")
}
if h == ts.Height() {
return ts, nil
}
if ts.Height()-h > build.ForkLengthThreshold {
log.Warnf("expensive call to GetTipsetByHeight, seeking %d levels", ts.Height()-h)
}
@ -955,6 +959,9 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h abi.ChainEpoch, t
if h > pts.Height() {
return ts, nil
}
if h == pts.Height() {
return pts, nil
}
ts = pts
}

View File

@ -519,6 +519,16 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
return xerrors.Errorf("load parent tipset failed (%s): %w", h.Parents, err)
}
lbts, err := stmgr.GetLookbackTipSetForRound(ctx, syncer.sm, baseTs, h.Height)
if err != nil {
return xerrors.Errorf("failed to get lookback tipset for block: %w", err)
}
lbst, _, err := syncer.sm.TipSetState(ctx, lbts)
if err != nil {
return xerrors.Errorf("failed to compute lookback tipset state: %w", err)
}
prevBeacon, err := syncer.store.GetLatestBeaconEntry(baseTs)
if err != nil {
return xerrors.Errorf("failed to get latest beacon entry: %w", err)
@ -585,7 +595,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
return xerrors.Errorf("parent receipts root did not match computed value (%s != %s)", precp, h.ParentMessageReceipts)
}
waddr, err := stmgr.GetMinerWorkerRaw(ctx, syncer.sm, stateroot, h.Miner)
waddr, err := stmgr.GetMinerWorkerRaw(ctx, syncer.sm, lbst, h.Miner)
if err != nil {
return xerrors.Errorf("GetMinerWorkerRaw failed: %w", err)
}
@ -620,7 +630,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
return xerrors.Errorf("received block was from slashed or invalid miner")
}
mpow, tpow, err := stmgr.GetPower(ctx, syncer.sm, baseTs, h.Miner)
mpow, tpow, err := stmgr.GetPowerRaw(ctx, syncer.sm, lbst, h.Miner)
if err != nil {
return xerrors.Errorf("failed getting power: %w", err)
}
@ -666,7 +676,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
})
wproofCheck := async.Err(func() error {
if err := syncer.VerifyWinningPoStProof(ctx, h, waddr); err != nil {
if err := syncer.VerifyWinningPoStProof(ctx, h, lbst, waddr); err != nil {
return xerrors.Errorf("invalid election post: %w", err)
}
return nil
@ -709,7 +719,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
return merr
}
func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.BlockHeader, waddr address.Address) error {
func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.BlockHeader, lbst cid.Cid, waddr address.Address) error {
if build.InsecurePoStValidation {
if len(h.WinPoStProof) == 0 {
return xerrors.Errorf("[TESTING] No winning post proof given")
@ -737,7 +747,7 @@ func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.Block
return xerrors.Errorf("failed to get ID from miner address %s: %w", h.Miner, err)
}
sectors, err := stmgr.GetSectorsForWinningPoSt(ctx, syncer.verifier, syncer.sm, curTs, h.Miner)
sectors, err := stmgr.GetSectorsForWinningPoSt(ctx, syncer.verifier, syncer.sm, lbst, h.Miner, rand)
if err != nil {
return xerrors.Errorf("getting winning post sector set: %w", err)
}

View File

@ -294,14 +294,15 @@ func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningB
log.Debugw("attempting to mine a block", "tipset", types.LogCids(base.ts.Cids()))
start := time.Now()
mbi, err := m.api.MinerGetBaseInfo(ctx, addr, base.ts.Key())
round := base.ts.Height() + base.nullRounds + 1
mbi, err := m.api.MinerGetBaseInfo(ctx, addr, round, base.ts.Key())
if err != nil {
return nil, xerrors.Errorf("failed to get mining base info: %w", err)
}
beaconPrev := mbi.PrevBeaconEntry
round := base.ts.Height() + base.nullRounds + 1
bvals, err := beacon.BeaconEntriesForBlock(ctx, m.beacon, round, beaconPrev)
if err != nil {
return nil, xerrors.Errorf("get beacon entries failed: %w", err)
@ -347,14 +348,7 @@ func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningB
prand := abi.PoStRandomness(rand)
sx, err := m.epp.GenerateCandidates(ctx, prand, uint64(len(mbi.Sectors)))
if err != nil {
return nil, xerrors.Errorf("failed to generate candidates for winning post: %w", err)
}
si := mbi.Sectors[sx[0]]
postInp := []abi.SectorInfo{si.Info.AsSectorInfo()}
postProof, err := m.epp.ComputeProof(ctx, postInp, prand)
postProof, err := m.epp.ComputeProof(ctx, mbi.Sectors, prand)
if err != nil {
return nil, xerrors.Errorf("failed to compute winning post proof: %w", err)
}

View File

@ -25,6 +25,7 @@ import (
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/lib/bufbstore"
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
@ -40,8 +41,9 @@ type StateAPI struct {
// API attached to the state API. It probably should live somewhere better
Wallet *wallet.Wallet
StateManager *stmgr.StateManager
Chain *store.ChainStore
ProofVerifier ffiwrapper.Verifier
StateManager *stmgr.StateManager
Chain *store.ChainStore
}
func (a *StateAPI) StateNetworkName(ctx context.Context) (dtypes.NetworkName, error) {
@ -252,8 +254,8 @@ func (a *StateAPI) StateReadState(ctx context.Context, act *types.Actor, tsk typ
}
// This is on StateAPI because miner.Miner requires this, and MinerAPI requires miner.Miner
func (a *StateAPI) MinerGetBaseInfo(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
return stmgr.MinerGetBaseInfo(ctx, a.StateManager, tsk, maddr)
func (a *StateAPI) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoch abi.ChainEpoch, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
return stmgr.MinerGetBaseInfo(ctx, a.StateManager, tsk, epoch, maddr, a.ProofVerifier)
}
func (a *StateAPI) MinerCreateBlock(ctx context.Context, bt *api.BlockTemplate) (*types.BlockMsg, error) {