les: fix light fetcher database race (#16103)

* les: fix light fetcher database race

* les: lightFetcher comments
This commit is contained in:
Felföldi Zsolt 2018-02-19 09:41:30 +01:00 committed by Péter Szilágyi
parent 06c5cae315
commit 1bdde620da

@ -36,24 +36,26 @@ const (
maxNodeCount = 20 // maximum number of fetcherTreeNode entries remembered for each peer maxNodeCount = 20 // maximum number of fetcherTreeNode entries remembered for each peer
) )
// lightFetcher // lightFetcher implements retrieval of newly announced headers. It also provides a peerHasBlock function for the
// ODR system to ensure that we only request data related to a certain block from peers who have already processed
// and announced that block.
type lightFetcher struct { type lightFetcher struct {
pm *ProtocolManager pm *ProtocolManager
odr *LesOdr odr *LesOdr
chain *light.LightChain chain *light.LightChain
lock sync.Mutex // lock protects access to the fetcher's internal state variables except sent requests
maxConfirmedTd *big.Int maxConfirmedTd *big.Int
peers map[*peer]*fetcherPeerInfo peers map[*peer]*fetcherPeerInfo
lastUpdateStats *updateStatsEntry lastUpdateStats *updateStatsEntry
syncing bool
syncDone chan *peer
lock sync.Mutex // qwerqwerqwe reqMu sync.RWMutex // reqMu protects access to sent header fetch requests
deliverChn chan fetchResponse
reqMu sync.RWMutex
requested map[uint64]fetchRequest requested map[uint64]fetchRequest
deliverChn chan fetchResponse
timeoutChn chan uint64 timeoutChn chan uint64
requestChn chan bool // true if initiated from outside requestChn chan bool // true if initiated from outside
syncing bool
syncDone chan *peer
} }
// fetcherPeerInfo holds fetcher-specific information about each active peer // fetcherPeerInfo holds fetcher-specific information about each active peer
@ -560,8 +562,13 @@ func (f *lightFetcher) checkAnnouncedHeaders(fp *fetcherPeerInfo, headers []*typ
return true return true
} }
// we ran out of recently delivered headers but have not reached a node known by this peer yet, continue matching // we ran out of recently delivered headers but have not reached a node known by this peer yet, continue matching
td = f.chain.GetTd(header.ParentHash, header.Number.Uint64()-1) hash, number := header.ParentHash, header.Number.Uint64()-1
header = f.chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) td = f.chain.GetTd(hash, number)
header = f.chain.GetHeader(hash, number)
if header == nil || td == nil {
log.Error("Missing parent of validated header", "hash", hash, "number", number)
return false
}
} else { } else {
header = headers[i] header = headers[i]
td = tds[i] td = tds[i]
@ -645,13 +652,18 @@ func (f *lightFetcher) checkKnownNode(p *peer, n *fetcherTreeNode) bool {
if td == nil { if td == nil {
return false return false
} }
header := f.chain.GetHeader(n.hash, n.number)
// check the availability of both header and td because reads are not protected by chain db mutex
// Note: returning false is always safe here
if header == nil {
return false
}
fp := f.peers[p] fp := f.peers[p]
if fp == nil { if fp == nil {
p.Log().Debug("Unknown peer to check known nodes") p.Log().Debug("Unknown peer to check known nodes")
return false return false
} }
header := f.chain.GetHeader(n.hash, n.number)
if !f.checkAnnouncedHeaders(fp, []*types.Header{header}, []*big.Int{td}) { if !f.checkAnnouncedHeaders(fp, []*types.Header{header}, []*big.Int{td}) {
p.Log().Debug("Inconsistent announcement") p.Log().Debug("Inconsistent announcement")
go f.pm.removePeer(p.id) go f.pm.removePeer(p.id)