eth/fetcher, eth/handler: differentiate metrics for all/useful broadcasts and announcements

This commit is contained in:
Martin Holst Swende 2020-01-22 21:21:44 +01:00
parent 7d665a80bc
commit f0da3e014c
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
4 changed files with 47 additions and 27 deletions

View file

@ -46,6 +46,9 @@ var (
// blockRetrievalFn is a callback type for retrieving a block from the local chain. // blockRetrievalFn is a callback type for retrieving a block from the local chain.
type blockRetrievalFn func(common.Hash) *types.Block type blockRetrievalFn func(common.Hash) *types.Block
// blockCheckFn is a callback type for checking if a given has exists in the local chain.
type blockCheckFn func(common.Hash) bool
// headerRequesterFn is a callback type for sending a header retrieval request. // headerRequesterFn is a callback type for sending a header retrieval request.
type headerRequesterFn func(common.Hash) error type headerRequesterFn func(common.Hash) error
@ -130,6 +133,7 @@ type Fetcher struct {
// Callbacks // Callbacks
getBlock blockRetrievalFn // Retrieves a block from the local chain getBlock blockRetrievalFn // Retrieves a block from the local chain
hasBlock blockCheckFn // Retrieves a block from the local chain
verifyHeader headerVerifierFn // Checks if a block's headers have a valid proof of work verifyHeader headerVerifierFn // Checks if a block's headers have a valid proof of work
broadcastBlock blockBroadcasterFn // Broadcasts a block to connected peers broadcastBlock blockBroadcasterFn // Broadcasts a block to connected peers
chainHeight chainHeightFn // Retrieves the current chain's height chainHeight chainHeightFn // Retrieves the current chain's height
@ -147,21 +151,23 @@ type Fetcher struct {
// New creates a block fetcher to retrieve blocks based on hash announcements. // New creates a block fetcher to retrieve blocks based on hash announcements.
func New(getBlock blockRetrievalFn, verifyHeader headerVerifierFn, broadcastBlock blockBroadcasterFn, chainHeight chainHeightFn, insertChain chainInsertFn, dropPeer peerDropFn) *Fetcher { func New(getBlock blockRetrievalFn, verifyHeader headerVerifierFn, broadcastBlock blockBroadcasterFn, chainHeight chainHeightFn, insertChain chainInsertFn, dropPeer peerDropFn) *Fetcher {
return &Fetcher{ return &Fetcher{
notify: make(chan *announce), notify: make(chan *announce),
inject: make(chan *inject), inject: make(chan *inject),
headerFilter: make(chan chan *headerFilterTask), headerFilter: make(chan chan *headerFilterTask),
bodyFilter: make(chan chan *bodyFilterTask), bodyFilter: make(chan chan *bodyFilterTask),
done: make(chan common.Hash), done: make(chan common.Hash),
quit: make(chan struct{}), quit: make(chan struct{}),
announces: make(map[string]int), announces: make(map[string]int),
announced: make(map[common.Hash][]*announce), announced: make(map[common.Hash][]*announce),
fetching: make(map[common.Hash]*announce), fetching: make(map[common.Hash]*announce),
fetched: make(map[common.Hash][]*announce), fetched: make(map[common.Hash][]*announce),
completing: make(map[common.Hash]*announce), completing: make(map[common.Hash]*announce),
queue: prque.New(nil), queue: prque.New(nil),
queues: make(map[string]int), queues: make(map[string]int),
queued: make(map[common.Hash]*inject), queued: make(map[common.Hash]*inject),
getBlock: getBlock, getBlock: getBlock,
// This can be replaced this with a more optimized lookup
hasBlock: func(hash common.Hash) bool { return getBlock(hash) != nil },
verifyHeader: verifyHeader, verifyHeader: verifyHeader,
broadcastBlock: broadcastBlock, broadcastBlock: broadcastBlock,
chainHeight: chainHeight, chainHeight: chainHeight,
@ -194,6 +200,7 @@ func (f *Fetcher) Notify(peer string, hash common.Hash, number uint64, time time
fetchHeader: headerFetcher, fetchHeader: headerFetcher,
fetchBodies: bodyFetcher, fetchBodies: bodyFetcher,
} }
propAnnounceUsefulInMeter.Mark(1)
select { select {
case f.notify <- block: case f.notify <- block:
return nil return nil
@ -204,6 +211,10 @@ func (f *Fetcher) Notify(peer string, hash common.Hash, number uint64, time time
// Enqueue tries to fill gaps the fetcher's future import queue. // Enqueue tries to fill gaps the fetcher's future import queue.
func (f *Fetcher) Enqueue(peer string, block *types.Block) error { func (f *Fetcher) Enqueue(peer string, block *types.Block) error {
if f.hasBlock(block.Hash()) {
return nil
}
propBroadcastUsefulMeter.Mark(1)
op := &inject{ op := &inject{
origin: peer, origin: peer,
block: block, block: block,
@ -304,7 +315,7 @@ func (f *Fetcher) loop() {
break break
} }
// Otherwise if fresh and still unknown, try and import // Otherwise if fresh and still unknown, try and import
if number+maxUncleDist < height || f.getBlock(hash) != nil { if number+maxUncleDist < height || f.hasBlock(hash) {
f.forgetBlock(hash) f.forgetBlock(hash)
continue continue
} }
@ -318,7 +329,6 @@ func (f *Fetcher) loop() {
case notification := <-f.notify: case notification := <-f.notify:
// A block was announced, make sure the peer isn't DOSing us // A block was announced, make sure the peer isn't DOSing us
propAnnounceInMeter.Mark(1)
count := f.announces[notification.origin] + 1 count := f.announces[notification.origin] + 1
if count > hashLimit { if count > hashLimit {
@ -352,7 +362,6 @@ func (f *Fetcher) loop() {
case op := <-f.inject: case op := <-f.inject:
// A direct block insertion was requested, try and fill any pending gaps // A direct block insertion was requested, try and fill any pending gaps
propBroadcastInMeter.Mark(1)
f.enqueue(op.origin, op.block) f.enqueue(op.origin, op.block)
case hash := <-f.done: case hash := <-f.done:
@ -371,7 +380,7 @@ func (f *Fetcher) loop() {
f.forgetHash(hash) f.forgetHash(hash)
// If the block still didn't arrive, queue for fetching // If the block still didn't arrive, queue for fetching
if f.getBlock(hash) == nil { if !f.hasBlock(hash) {
request[announce.origin] = append(request[announce.origin], hash) request[announce.origin] = append(request[announce.origin], hash)
f.fetching[hash] = announce f.fetching[hash] = announce
} }
@ -406,7 +415,7 @@ func (f *Fetcher) loop() {
f.forgetHash(hash) f.forgetHash(hash)
// If the block still didn't arrive, queue for completion // If the block still didn't arrive, queue for completion
if f.getBlock(hash) == nil { if !f.hasBlock(hash) {
request[announce.origin] = append(request[announce.origin], hash) request[announce.origin] = append(request[announce.origin], hash)
f.completing[hash] = announce f.completing[hash] = announce
} }
@ -453,7 +462,7 @@ func (f *Fetcher) loop() {
continue continue
} }
// Only keep if not imported by other means // Only keep if not imported by other means
if f.getBlock(hash) == nil { if !f.hasBlock(hash) {
announce.header = header announce.header = header
announce.time = task.time announce.time = task.time
@ -527,7 +536,7 @@ func (f *Fetcher) loop() {
// Mark the body matched, reassemble if still unknown // Mark the body matched, reassemble if still unknown
matched = true matched = true
if f.getBlock(hash) == nil { if !f.hasBlock(hash) {
block := types.NewBlockWithHeader(announce.header).WithBody(task.transactions[i], task.uncles[i]) block := types.NewBlockWithHeader(announce.header).WithBody(task.transactions[i], task.uncles[i])
block.ReceivedAt = task.time block.ReceivedAt = task.time

View file

@ -23,12 +23,17 @@ import (
) )
var ( var (
propAnnounceInMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/announces/in", nil)
// Useful block announcements == announcements we did not already know about
propAnnounceUsefulInMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/announces/useful", nil)
propAnnounceOutTimer = metrics.NewRegisteredTimer("eth/fetcher/prop/announces/out", nil) propAnnounceOutTimer = metrics.NewRegisteredTimer("eth/fetcher/prop/announces/out", nil)
propAnnounceDropMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/announces/drop", nil) propAnnounceDropMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/announces/drop", nil)
propAnnounceDOSMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/announces/dos", nil) propAnnounceDOSMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/announces/dos", nil)
propBroadcastInMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/broadcasts/in", nil) // All useful incoming block broadcasts == broadcasts we did not already have
propBroadcastUsefulMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/broadcasts/useful", nil)
propBroadcastOutTimer = metrics.NewRegisteredTimer("eth/fetcher/prop/broadcasts/out", nil) propBroadcastOutTimer = metrics.NewRegisteredTimer("eth/fetcher/prop/broadcasts/out", nil)
propBroadcastDropMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/broadcasts/drop", nil) propBroadcastDropMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/broadcasts/drop", nil)
propBroadcastDOSMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/broadcasts/dos", nil) propBroadcastDOSMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/broadcasts/dos", nil)

View file

@ -670,6 +670,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
for _, block := range announces { for _, block := range announces {
p.MarkBlock(block.Hash) p.MarkBlock(block.Hash)
} }
propAnnounceAllInMeter.Mark(int64(len(announces)))
// Schedule all the unknown hashes for retrieval // Schedule all the unknown hashes for retrieval
unknown := make(newBlockHashesData, 0, len(announces)) unknown := make(newBlockHashesData, 0, len(announces))
for _, block := range announces { for _, block := range announces {
@ -687,6 +688,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
if err := msg.Decode(&request); err != nil { if err := msg.Decode(&request); err != nil {
return errResp(ErrDecode, "%v: %v", msg, err) return errResp(ErrDecode, "%v: %v", msg, err)
} }
propBroadcastAllInMeter.Mark(1)
if hash := types.CalcUncleHash(request.Block.Uncles()); hash != request.Block.UncleHash() { if hash := types.CalcUncleHash(request.Block.Uncles()); hash != request.Block.UncleHash() {
log.Warn("Propagated block has invalid uncles", "have", hash, "exp", request.Block.UncleHash()) log.Warn("Propagated block has invalid uncles", "have", hash, "exp", request.Block.UncleHash())
break // TODO(karalabe): return error eventually, but wait a few releases break // TODO(karalabe): return error eventually, but wait a few releases
@ -703,9 +705,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
// Mark the peer as owning the block and schedule it for import // Mark the peer as owning the block and schedule it for import
p.MarkBlock(request.Block.Hash()) p.MarkBlock(request.Block.Hash())
if !pm.blockchain.HasBlock(request.Block.Hash(), request.Block.NumberU64()) { pm.fetcher.Enqueue(p.id, request.Block)
pm.fetcher.Enqueue(p.id, request.Block)
}
// Assuming the block is importable by the peer, but possibly not yet done so, // Assuming the block is importable by the peer, but possibly not yet done so,
// calculate the head hash and TD that the peer truly must have. // calculate the head hash and TD that the peer truly must have.
var ( var (

View file

@ -54,6 +54,11 @@ var (
miscInTrafficMeter = metrics.NewRegisteredMeter("eth/misc/in/traffic", nil) miscInTrafficMeter = metrics.NewRegisteredMeter("eth/misc/in/traffic", nil)
miscOutPacketsMeter = metrics.NewRegisteredMeter("eth/misc/out/packets", nil) miscOutPacketsMeter = metrics.NewRegisteredMeter("eth/misc/out/packets", nil)
miscOutTrafficMeter = metrics.NewRegisteredMeter("eth/misc/out/traffic", nil) miscOutTrafficMeter = metrics.NewRegisteredMeter("eth/misc/out/traffic", nil)
// All incoming block announcements (no dedup)
propAnnounceAllInMeter = metrics.NewRegisteredMeter("eth/announces/block/in/all", nil)
// All incoming block broadcasts
propBroadcastAllInMeter = metrics.NewRegisteredMeter("eth/broadcasts/block/in/all", nil)
) )
// meteredMsgReadWriter is a wrapper around a p2p.MsgReadWriter, capable of // meteredMsgReadWriter is a wrapper around a p2p.MsgReadWriter, capable of