diff --git a/api/api_full.go b/api/api_full.go index b47d10d03..6e9b999de 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -107,6 +107,14 @@ type FullNode interface { // ChainExport returns a stream of bytes with CAR dump of chain data. ChainExport(context.Context, types.TipSetKey) (<-chan []byte, error) + // MethodGroup: Beacon + // The Beacon method group contains methods for interacting with the random beacon (DRAND) + + // BeaconGetEntry returns the beacon entry for the given filecoin epoch. If + // the entry has not yet been produced, the call will block until the entry + // becomes available + BeaconGetEntry(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) + // GasEstimateGasLimit estimates gas used by the message and returns it. // It fails if message fails to execute. GasEstimateGasLimit(context.Context, *types.Message, types.TipSetKey) (int64, error) diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index 6481223da..561783abc 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -85,6 +85,8 @@ type FullNodeStruct struct { ChainGetPath func(context.Context, types.TipSetKey, types.TipSetKey) ([]*api.HeadChange, error) `perm:"read"` ChainExport func(context.Context, types.TipSetKey) (<-chan []byte, error) `perm:"read"` + BeaconGetEntry func(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"` + GasEstimateGasPrice func(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"` GasEstimateGasLimit func(context.Context, *types.Message, types.TipSetKey) (int64, error) `perm:"read"` @@ -598,6 +600,10 @@ func (c *FullNodeStruct) ChainExport(ctx context.Context, tsk types.TipSetKey) ( return c.Internal.ChainExport(ctx, tsk) } +func (c *FullNodeStruct) BeaconGetEntry(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) { + return c.Internal.BeaconGetEntry(ctx, epoch) +} + func (c *FullNodeStruct) SyncState(ctx context.Context) (*api.SyncState, error) { return c.Internal.SyncState(ctx) } diff --git a/miner/miner.go b/miner/miner.go index 709424aba..61a5e1bb0 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -147,25 +147,39 @@ func (m *Miner) mine(ctx context.Context) { default: } - prebase, err := m.GetBestMiningCandidate(ctx) - if err != nil { - log.Errorf("failed to get best mining candidate: %s", err) - m.niceSleep(time.Second * 5) - continue + var base *MiningBase + var onDone func(bool, error) + var injectNulls abi.ChainEpoch + + for { + prebase, err := m.GetBestMiningCandidate(ctx) + if err != nil { + log.Errorf("failed to get best mining candidate: %s", err) + m.niceSleep(time.Second * 5) + continue + } + + if base != nil && base.TipSet.Height() == prebase.TipSet.Height() && base.NullRounds == prebase.NullRounds { + break + } + + // Wait until propagation delay period after block we plan to mine on + onDone, injectNulls, err = m.waitFunc(ctx, prebase.TipSet.MinTimestamp()) + if err != nil { + log.Error(err) + continue + } + + // just wait for the beacon entry to become available before we select our final mining base + _, err = m.api.BeaconGetEntry(ctx, prebase.TipSet.Height()+prebase.NullRounds+1) + if err != nil { + log.Errorf("failed getting beacon entry: %s", err) + continue + } + + base = prebase } - // Wait until propagation delay period after block we plan to mine on - onDone, injectNulls, err := m.waitFunc(ctx, prebase.TipSet.MinTimestamp()) - if err != nil { - log.Error(err) - continue - } - - base, err := m.GetBestMiningCandidate(ctx) - if err != nil { - log.Errorf("failed to get best mining candidate: %s", err) - continue - } if base.TipSet.Equals(lastBase.TipSet) && lastBase.NullRounds == base.NullRounds { log.Warnf("BestMiningCandidate from the previous round: %s (nulls:%d)", lastBase.TipSet.Cids(), lastBase.NullRounds) m.niceSleep(time.Duration(build.BlockDelaySecs) * time.Second)