Skip to content

Commit 1bdde62

Browse files
zsfelfoldikaralabe
authored andcommitted
les: fix light fetcher database race (ethereum#16103)
* les: fix light fetcher database race * les: lightFetcher comments
1 parent 06c5cae commit 1bdde62

File tree

1 file changed

+21
-9
lines changed

1 file changed

+21
-9
lines changed

les/fetcher.go

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,24 +36,26 @@ const (
3636
maxNodeCount = 20 // maximum number of fetcherTreeNode entries remembered for each peer
3737
)
3838

39-
// lightFetcher
39+
// lightFetcher implements retrieval of newly announced headers. It also provides a peerHasBlock function for the
40+
// ODR system to ensure that we only request data related to a certain block from peers who have already processed
41+
// and announced that block.
4042
type lightFetcher struct {
4143
pm *ProtocolManager
4244
odr *LesOdr
4345
chain *light.LightChain
4446

47+
lock sync.Mutex // lock protects access to the fetcher's internal state variables except sent requests
4548
maxConfirmedTd *big.Int
4649
peers map[*peer]*fetcherPeerInfo
4750
lastUpdateStats *updateStatsEntry
51+
syncing bool
52+
syncDone chan *peer
4853

49-
lock sync.Mutex // qwerqwerqwe
50-
deliverChn chan fetchResponse
51-
reqMu sync.RWMutex
54+
reqMu sync.RWMutex // reqMu protects access to sent header fetch requests
5255
requested map[uint64]fetchRequest
56+
deliverChn chan fetchResponse
5357
timeoutChn chan uint64
5458
requestChn chan bool // true if initiated from outside
55-
syncing bool
56-
syncDone chan *peer
5759
}
5860

5961
// fetcherPeerInfo holds fetcher-specific information about each active peer
@@ -560,8 +562,13 @@ func (f *lightFetcher) checkAnnouncedHeaders(fp *fetcherPeerInfo, headers []*typ
560562
return true
561563
}
562564
// we ran out of recently delivered headers but have not reached a node known by this peer yet, continue matching
563-
td = f.chain.GetTd(header.ParentHash, header.Number.Uint64()-1)
564-
header = f.chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
565+
hash, number := header.ParentHash, header.Number.Uint64()-1
566+
td = f.chain.GetTd(hash, number)
567+
header = f.chain.GetHeader(hash, number)
568+
if header == nil || td == nil {
569+
log.Error("Missing parent of validated header", "hash", hash, "number", number)
570+
return false
571+
}
565572
} else {
566573
header = headers[i]
567574
td = tds[i]
@@ -645,13 +652,18 @@ func (f *lightFetcher) checkKnownNode(p *peer, n *fetcherTreeNode) bool {
645652
if td == nil {
646653
return false
647654
}
655+
header := f.chain.GetHeader(n.hash, n.number)
656+
// check the availability of both header and td because reads are not protected by chain db mutex
657+
// Note: returning false is always safe here
658+
if header == nil {
659+
return false
660+
}
648661

649662
fp := f.peers[p]
650663
if fp == nil {
651664
p.Log().Debug("Unknown peer to check known nodes")
652665
return false
653666
}
654-
header := f.chain.GetHeader(n.hash, n.number)
655667
if !f.checkAnnouncedHeaders(fp, []*types.Header{header}, []*big.Int{td}) {
656668
p.Log().Debug("Inconsistent announcement")
657669
go f.pm.removePeer(p.id)

0 commit comments

Comments
 (0)