From 91d2c027656a2974cab41506224d91a96897e958 Mon Sep 17 00:00:00 2001 From: Aayush <arajasek94@gmail.com> Date: Thu, 10 Aug 2023 16:07:08 -0400 Subject: [PATCH] feat: miner: implement FRC-0051 --- build/params_mainnet.go | 1 + miner/miner.go | 43 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/build/params_mainnet.go b/build/params_mainnet.go index 0b3c0a254..9026056c0 100644 --- a/build/params_mainnet.go +++ b/build/params_mainnet.go @@ -105,6 +105,7 @@ var SupportedProofTypes = []abi.RegisteredSealProof{ var ConsensusMinerMinPower = abi.NewStoragePower(10 << 40) var PreCommitChallengeDelay = abi.ChainEpoch(150) var PropagationDelaySecs = uint64(10) +var EquivocationDelaySecs = uint64(2) func init() { if os.Getenv("LOTUS_USE_TEST_ADDRESSES") != "1" { diff --git a/miner/miner.go b/miner/miner.go index 104cf35fc..b02aba69d 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -10,7 +10,7 @@ import ( "sync" "time" - "github.com/hashicorp/golang-lru/arc/v2" + "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" "go.opencensus.io/trace" "golang.org/x/xerrors" @@ -373,8 +373,9 @@ minerLoop: // MiningBase is the tipset on top of which we plan to construct our next block. // Refer to godocs on GetBestMiningCandidate. type MiningBase struct { - TipSet *types.TipSet - NullRounds abi.ChainEpoch + TipSet *types.TipSet + ComputeTime time.Time + NullRounds abi.ChainEpoch } // GetBestMiningCandidate implements the fork choice rule from a miner's @@ -412,7 +413,7 @@ func (m *Miner) GetBestMiningCandidate(ctx context.Context) (*MiningBase, error) } } - m.lastWork = &MiningBase{TipSet: bts} + m.lastWork = &MiningBase{TipSet: bts, ComputeTime: time.Now()} return m.lastWork, nil } @@ -560,6 +561,37 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (minedBlock *type return nil, err } + tEquivocateWait := build.Clock.Now() + + // TODO: make param + m.niceSleep(time.Until(base.ComputeTime.Add(2 * time.Second))) + newBase, err := m.GetBestMiningCandidate(ctx) + if err != nil { + err = xerrors.Errorf("failed to refresh best mining candidate: %w", err) + return nil, err + } + + // Only factor in equivocated blocks if doing so will not risk us missing a block + if newBase.TipSet.Height() == base.TipSet.Height() && newBase.TipSet.MinTicket().Equals(base.TipSet.MinTicket()) { + newBaseMap := map[cid.Cid]struct{}{} + for _, newBaseBlk := range newBase.TipSet.Cids() { + newBaseMap[newBaseBlk] = struct{}{} + } + + refreshedBase := make([]*types.BlockHeader, 0, len(base.TipSet.Cids())) + for _, baseBlk := range base.TipSet.Blocks() { + if _, ok := newBaseMap[baseBlk.Cid()]; ok { + refreshedBase = append(refreshedBase, baseBlk) + } + } + + base.TipSet, err = types.NewTipSet(refreshedBase) + if err != nil { + err = xerrors.Errorf("failed to create new tipset when refreshing: %w", err) + return nil, err + } + } + tPending := build.Clock.Now() // TODO: winning post proof @@ -582,7 +614,8 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (minedBlock *type "tTicket ", tTicket.Sub(tPowercheck), "tSeed ", tSeed.Sub(tTicket), "tProof ", tProof.Sub(tSeed), - "tPending ", tPending.Sub(tProof), + "tEquivocateWait ", tEquivocateWait.Sub(tProof), + "tPending ", tPending.Sub(tEquivocateWait), "tCreateBlock ", tCreateBlock.Sub(tPending)) }