Use sync rate for getBlockTemplate's isSynced (#1311)

* Use sync rate for getBlockTemplate's isSynced

* Fix a typo

Co-authored-by: Mike Zak <feanorr@gmail.com>
This commit is contained in:
Ori Newman 2020-12-29 09:28:02 +02:00 committed by GitHub
parent 4aafe8a630
commit 5f22632836
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 96 additions and 4 deletions

View File

@ -23,6 +23,8 @@ func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock,
hash := consensushashing.BlockHash(block)
log.Debugf("OnNewBlock start for block %s", hash)
defer log.Debugf("OnNewBlock end for block %s", hash)
f.updateRecentBlockAddedTimesWithLastBlock()
unorphaningResults, err := f.UnorphanBlocks(block)
if err != nil {
return err

View File

@ -1,6 +1,7 @@
package flowcontext
import (
"github.com/kaspanet/kaspad/util/mstime"
"sync"
"time"
@ -35,6 +36,11 @@ type FlowContext struct {
addressManager *addressmanager.AddressManager
connectionManager *connmanager.ConnectionManager
recentBlockAddedTimes []int64
recentBlockAddedTimesMutex sync.Mutex
timeStarted int64
onBlockAddedToDAGHandler OnBlockAddedToDAGHandler
onTransactionAddedToMempoolHandler OnTransactionAddedToMempoolHandler
@ -69,6 +75,7 @@ func New(cfg *config.Config, domain domain.Domain, addressManager *addressmanage
peers: make(map[id.ID]*peerpkg.Peer),
transactionsToRebroadcast: make(map[externalapi.DomainTransactionID]*externalapi.DomainTransaction),
orphans: make(map[externalapi.DomainHash]*externalapi.DomainBlock),
timeStarted: mstime.Now().UnixMilliseconds(),
}
}

View File

@ -156,6 +156,7 @@ func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) (*externa
}
return nil, false, err
}
f.updateRecentBlockAddedTimesWithLastBlock()
log.Infof("Unorphaned block %s", orphanHash)
return blockInsertionResult, true, nil

View File

@ -0,0 +1,78 @@
package flowcontext
import "github.com/kaspanet/kaspad/util/mstime"
const (
syncRateWindowInMilliSeconds = 60_000
syncRateMaxDeviation = 0.05
maxSelectedParentTimeDiffToAllowMiningInMilliSeconds = 300_000
)
func (f *FlowContext) updateRecentBlockAddedTimesWithLastBlock() {
f.recentBlockAddedTimesMutex.Lock()
defer f.recentBlockAddedTimesMutex.Unlock()
f.removeOldBlockTimes()
f.recentBlockAddedTimes = append(f.recentBlockAddedTimes, mstime.Now().UnixMilliseconds())
}
// removeOldBlockTimes removes from recentBlockAddedTimes block times
// older than syncRateWindowInMilliSeconds.
// This function is not safe for concurrent use.
func (f *FlowContext) removeOldBlockTimes() {
now := mstime.Now().UnixMilliseconds()
mostRecentBlockToKeep := 0
for i, blockAddedTime := range f.recentBlockAddedTimes {
if now-syncRateWindowInMilliSeconds < blockAddedTime {
mostRecentBlockToKeep = i
break
}
}
f.recentBlockAddedTimes = f.recentBlockAddedTimes[mostRecentBlockToKeep:]
}
func (f *FlowContext) isSyncRateBelowMinimum() bool {
f.recentBlockAddedTimesMutex.Lock()
defer f.recentBlockAddedTimesMutex.Unlock()
f.removeOldBlockTimes()
now := mstime.Now().UnixMilliseconds()
timeSinceStart := now - f.timeStarted
if timeSinceStart <= syncRateWindowInMilliSeconds {
return false
}
expectedBlocks := float64(syncRateWindowInMilliSeconds) / float64(f.cfg.NetParams().TargetTimePerBlock.Milliseconds())
return 1-float64(len(f.recentBlockAddedTimes))/expectedBlocks > syncRateMaxDeviation
}
// ShouldMine returns whether it's ok to use block template from this node
// for mining purposes.
func (f *FlowContext) ShouldMine() (bool, error) {
if f.isSyncRateBelowMinimum() {
log.Debugf("The sync rate is below the minimum, so ShouldMine returns true")
return true, nil
}
if f.IsIBDRunning() {
log.Debugf("IBD is running, so ShouldMine returns false")
return false, nil
}
virtualSelectedParent, err := f.domain.Consensus().GetVirtualSelectedParent()
if err != nil {
return false, err
}
now := mstime.Now().UnixMilliseconds()
if now-virtualSelectedParent.Header.TimeInMilliseconds < maxSelectedParentTimeDiffToAllowMiningInMilliSeconds {
log.Debugf("The selected tip timestamp is recent (%d), so ShouldMine returns true",
virtualSelectedParent.Header.TimeInMilliseconds)
return true, nil
}
log.Debugf("The selected tip timestamp is old (%d), so ShouldMine returns false",
virtualSelectedParent.Header.TimeInMilliseconds)
return false, nil
}

View File

@ -68,7 +68,8 @@ func (m *Manager) SetOnTransactionAddedToMempoolHandler(onTransactionAddedToMemp
m.context.SetOnTransactionAddedToMempoolHandler(onTransactionAddedToMempoolHandler)
}
// IsIBDRunning returns true if IBD is currently running
func (m *Manager) IsIBDRunning() bool {
return m.context.IsIBDRunning()
// ShouldMine returns whether it's ok to use block template from this node
// for mining purposes.
func (m *Manager) ShouldMine() (bool, error) {
return m.context.ShouldMine()
}

View File

@ -33,7 +33,10 @@ func HandleGetBlockTemplate(context *rpccontext.Context, _ *router.Router, reque
}
msgBlock := appmessage.DomainBlockToMsgBlock(templateBlock)
isSynced := !context.ProtocolManager.IsIBDRunning()
isSynced, err := context.ProtocolManager.ShouldMine()
if err != nil {
return nil, err
}
return appmessage.NewGetBlockTemplateResponseMessage(msgBlock, isSynced), nil
}