diff --git a/api/api_full.go b/api/api_full.go index 05cffc05f..a1c21344c 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -72,6 +72,7 @@ type FullNode interface { // miner + MinerGetBaseInfo(context.Context, address.Address, types.TipSetKey) (*MiningBaseInfo, error) MinerCreateBlock(context.Context, address.Address, types.TipSetKey, *types.Ticket, *types.EPostProof, []*types.SignedMessage, abi.ChainEpoch, uint64) (*types.BlockMsg, error) // // UX ? @@ -376,3 +377,11 @@ type ComputeStateOutput struct { Root cid.Cid Trace []*InvocResult } + +type MiningBaseInfo struct { + MinerPower types.BigInt + NetworkPower types.BigInt + Sectors []*ChainSectorInfo + Worker address.Address + SectorSize abi.SectorSize +} diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index 563afcfd7..d809c8a25 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -22,7 +22,7 @@ import ( "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/modules/dtypes" - "github.com/filecoin-project/sector-storage" + sectorstorage "github.com/filecoin-project/sector-storage" "github.com/filecoin-project/sector-storage/sealtasks" "github.com/filecoin-project/sector-storage/stores" ) @@ -87,6 +87,7 @@ 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, address.Address, types.TipSetKey, *types.Ticket, *types.EPostProof, []*types.SignedMessage, abi.ChainEpoch, uint64) (*types.BlockMsg, error) `perm:"write"` WalletNew func(context.Context, crypto.SigType) (address.Address, error) `perm:"write"` @@ -323,6 +324,10 @@ 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) MinerCreateBlock(ctx context.Context, addr address.Address, base types.TipSetKey, ticket *types.Ticket, eproof *types.EPostProof, msgs []*types.SignedMessage, height abi.ChainEpoch, ts uint64) (*types.BlockMsg, error) { return c.Internal.MinerCreateBlock(ctx, addr, base, ticket, eproof, msgs, height, ts) } diff --git a/chain/gen/gen.go b/chain/gen/gen.go index a8eeb54f0..9becb17d4 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -446,13 +446,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) - StateMinerPower(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) - - StateMinerWorker(context.Context, address.Address, types.TipSetKey) (address.Address, error) - - StateMinerSectorSize(context.Context, address.Address, types.TipSetKey) (abi.SectorSize, error) - - StateMinerProvingSet(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) + MinerGetBaseInfo(context.Context, address.Address, types.TipSetKey) (*api.MiningBaseInfo, error) WalletSign(context.Context, address.Address, []byte) (*crypto.Signature, error) } @@ -471,44 +465,8 @@ func (mca mca) ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, pers return mca.sm.ChainStore().GetRandomness(ctx, pts.Cids(), personalization, int64(randEpoch), entropy) } -func (mca mca) StateMinerPower(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (*api.MinerPower, error) { - ts, err := mca.sm.ChainStore().LoadTipSet(tsk) - if err != nil { - return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) - } - mpow, tpow, err := stmgr.GetPower(ctx, mca.sm, ts, maddr) - if err != nil { - return nil, err - } - - return &api.MinerPower{ - MinerPower: mpow, - TotalPower: tpow, - }, err -} - -func (mca mca) StateMinerWorker(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (address.Address, error) { - ts, err := mca.sm.ChainStore().LoadTipSet(tsk) - if err != nil { - return address.Undef, xerrors.Errorf("loading tipset %s: %w", tsk, err) - } - return stmgr.GetMinerWorkerRaw(ctx, mca.sm, ts.ParentState(), maddr) -} - -func (mca mca) StateMinerSectorSize(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (abi.SectorSize, error) { - ts, err := mca.sm.ChainStore().LoadTipSet(tsk) - if err != nil { - return 0, xerrors.Errorf("loading tipset %s: %w", tsk, err) - } - return stmgr.GetMinerSectorSize(ctx, mca.sm, ts, maddr) -} - -func (mca mca) StateMinerProvingSet(ctx context.Context, maddr address.Address, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) { - ts, err := mca.sm.ChainStore().LoadTipSet(tsk) - if err != nil { - return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) - } - return stmgr.GetMinerProvingSet(ctx, mca.sm, ts, maddr) +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) WalletSign(ctx context.Context, a address.Address, v []byte) (*crypto.Signature, error) { @@ -560,26 +518,22 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner add return nil, xerrors.Errorf("chain get randomness: %w", err) } - mworker, err := a.StateMinerWorker(ctx, miner, ts.Key()) + mbi, err := a.MinerGetBaseInfo(ctx, miner, ts.Key()) if err != nil { - return nil, xerrors.Errorf("failed to get miner worker: %w", err) + return nil, xerrors.Errorf("failed to get mining base info: %w", err) } - vrfout, err := ComputeVRF(ctx, a.WalletSign, mworker, epostRand) + vrfout, err := ComputeVRF(ctx, a.WalletSign, mbi.Worker, epostRand) if err != nil { return nil, xerrors.Errorf("failed to compute VRF: %w", err) } - pset, err := a.StateMinerProvingSet(ctx, miner, ts.Key()) - if err != nil { - return nil, xerrors.Errorf("failed to load proving set for miner: %w", err) - } - if len(pset) == 0 { + if len(mbi.Sectors) == 0 { return nil, nil } var sinfos []abi.SectorInfo - for _, s := range pset { + for _, s := range mbi.Sectors { if s.Info.Info.RegisteredProof == 0 { return nil, xerrors.Errorf("sector %d in proving set had registered type of zero", s.ID) } @@ -596,19 +550,9 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner add return nil, xerrors.Errorf("failed to generate electionPoSt candidates: %w", err) } - pow, err := a.StateMinerPower(ctx, miner, ts.Key()) - if err != nil { - return nil, xerrors.Errorf("failed to check power: %w", err) - } - - ssize, err := a.StateMinerSectorSize(ctx, miner, ts.Key()) - if err != nil { - return nil, xerrors.Errorf("failed to look up miners sector size: %w", err) - } - var winners []storage.PoStCandidateWithTicket for _, c := range candidates { - if types.IsTicketWinner(c.Candidate.PartialTicket, ssize, uint64(len(sinfos)), pow.TotalPower) { + if types.IsTicketWinner(c.Candidate.PartialTicket, mbi.SectorSize, uint64(len(sinfos)), mbi.NetworkPower) { winners = append(winners, c) } } diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index d4b2ff5b5..ade76c2a6 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -74,8 +74,12 @@ func GetMinerOwner(ctx context.Context, sm *StateManager, st cid.Cid, maddr addr } func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (types.BigInt, types.BigInt, error) { + return getPowerRaw(ctx, sm, ts.ParentState(), maddr) +} + +func getPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (types.BigInt, types.BigInt, error) { var ps power.State - _, err := sm.LoadActorState(ctx, builtin.StoragePowerActorAddr, &ps, ts) + _, err := sm.LoadActorStateRaw(ctx, builtin.StoragePowerActorAddr, &ps, st) if err != nil { return big.Zero(), big.Zero(), xerrors.Errorf("(get sset) failed to load power actor state: %w", err) } @@ -142,8 +146,12 @@ func SectorSetSizes(ctx context.Context, sm *StateManager, maddr address.Address } func GetMinerProvingSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]*api.ChainSectorInfo, error) { + return getMinerProvingSetRaw(ctx, sm, ts.ParentState(), maddr) +} + +func getMinerProvingSetRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) ([]*api.ChainSectorInfo, error) { var mas miner.State - _, err := sm.LoadActorState(ctx, maddr, &mas, ts) + _, err := sm.LoadActorStateRaw(ctx, maddr, &mas, st) if err != nil { return nil, xerrors.Errorf("(get pset) failed to load miner actor state: %w", err) } @@ -180,8 +188,12 @@ func GetSectorsForElectionPost(ctx context.Context, sm *StateManager, ts *types. } func GetMinerSectorSize(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (abi.SectorSize, error) { + return getMinerSectorSizeRaw(ctx, sm, ts.ParentState(), maddr) +} + +func getMinerSectorSizeRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (abi.SectorSize, error) { var mas miner.State - _, err := sm.LoadActorState(ctx, maddr, &mas, ts) + _, err := sm.LoadActorStateRaw(ctx, maddr, &mas, st) if err != nil { return 0, xerrors.Errorf("(get ssize) failed to load miner actor state: %w", err) } @@ -357,3 +369,43 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, return root, trace, nil } + +func MinerGetBaseInfo(ctx context.Context, sm *StateManager, tsk types.TipSetKey, maddr address.Address) (*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) + if err != nil { + return nil, err + } + + provset, err := getMinerProvingSetRaw(ctx, sm, st, maddr) + if err != nil { + return nil, xerrors.Errorf("failed to get proving set: %w", err) + } + + mpow, tpow, err := getPowerRaw(ctx, sm, st, maddr) + if err != nil { + return nil, xerrors.Errorf("failed to get power: %w", err) + } + + worker, err := GetMinerWorkerRaw(ctx, sm, st, maddr) + if err != nil { + return nil, xerrors.Errorf("failed to get miner worker: %w", err) + } + + ssize, err := getMinerSectorSizeRaw(ctx, sm, st, maddr) + if err != nil { + return nil, xerrors.Errorf("failed to get miner sector size: %w", err) + } + + return &api.MiningBaseInfo{ + MinerPower: mpow, + NetworkPower: tpow, + Sectors: provset, + Worker: worker, + SectorSize: ssize, + }, nil +} diff --git a/chain/sync.go b/chain/sync.go index bbbbfefc7..77222a90a 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -635,7 +635,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err }) eproofCheck := async.Err(func() error { - if err := syncer.VerifyElectionPoStProof(ctx, h, baseTs, waddr); err != nil { + if err := syncer.VerifyElectionPoStProof(ctx, h, waddr); err != nil { return xerrors.Errorf("invalid election post: %w", err) } return nil @@ -677,12 +677,17 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err return merr } -func (syncer *Syncer) VerifyElectionPoStProof(ctx context.Context, h *types.BlockHeader, baseTs *types.TipSet, waddr address.Address) error { +func (syncer *Syncer) VerifyElectionPoStProof(ctx context.Context, h *types.BlockHeader, waddr address.Address) error { + curTs, err := types.NewTipSet([]*types.BlockHeader{h}) + if err != nil { + return err + } + buf := new(bytes.Buffer) if err := h.Miner.MarshalCBOR(buf); err != nil { return xerrors.Errorf("failed to marshal miner to cbor: %w", err) } - rand, err := syncer.sm.ChainStore().GetRandomness(ctx, baseTs.Cids(), crypto.DomainSeparationTag_ElectionPoStChallengeSeed, int64(h.Height-build.EcRandomnessLookback), buf.Bytes()) + rand, err := syncer.sm.ChainStore().GetRandomness(ctx, curTs.Cids(), crypto.DomainSeparationTag_ElectionPoStChallengeSeed, int64(h.Height-build.EcRandomnessLookback), buf.Bytes()) if err != nil { return xerrors.Errorf("failed to get randomness for verifying election proof: %w", err) } @@ -691,7 +696,7 @@ func (syncer *Syncer) VerifyElectionPoStProof(ctx context.Context, h *types.Bloc return xerrors.Errorf("checking eproof failed: %w", err) } - ssize, err := stmgr.GetMinerSectorSize(ctx, syncer.sm, baseTs, h.Miner) + ssize, err := stmgr.GetMinerSectorSize(ctx, syncer.sm, curTs, h.Miner) if err != nil { return xerrors.Errorf("failed to get sector size for miner: %w", err) } @@ -717,7 +722,7 @@ func (syncer *Syncer) VerifyElectionPoStProof(ctx context.Context, h *types.Bloc return xerrors.Errorf("no candidates") } - sectorInfo, err := stmgr.GetSectorsForElectionPost(ctx, syncer.sm, baseTs, h.Miner) + sectorInfo, err := stmgr.GetSectorsForElectionPost(ctx, syncer.sm, curTs, h.Miner) if err != nil { return xerrors.Errorf("getting election post sector set: %w", err) } diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 407ea2767..023faa3b2 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -263,6 +263,11 @@ func (a *StateAPI) StateReadState(ctx context.Context, act *types.Actor, tsk typ }, nil } +// 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) +} + // This is on StateAPI because miner.Miner requires this, and MinerAPI requires miner.Miner func (a *StateAPI) MinerCreateBlock(ctx context.Context, addr address.Address, parentsTSK types.TipSetKey, ticket *types.Ticket, proof *types.EPostProof, msgs []*types.SignedMessage, height abi.ChainEpoch, ts uint64) (*types.BlockMsg, error) { parents, err := a.Chain.GetTipSetFromKey(parentsTSK)