mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
eth/fetcher, eth/handler: differentiate metrics for all/useful broadcasts and announcements
This commit is contained in:
parent
7d665a80bc
commit
f0da3e014c
4 changed files with 47 additions and 27 deletions
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue