diff options
author | Felföldi Zsolt <zsfelfoldi@gmail.com> | 2018-02-19 16:41:30 +0800 |
---|---|---|
committer | Péter Szilágyi <peterke@gmail.com> | 2018-02-19 16:41:30 +0800 |
commit | 1bdde620dad3c5fccb8e5de19fe7f42b1209a156 (patch) | |
tree | 952ec4a208b3ed2db4bde4487a0a368f6b7817a9 | |
parent | 06c5cae3158dfdd4c528ce17b6fc793f3198ee64 (diff) | |
download | go-tangerine-1bdde620dad3c5fccb8e5de19fe7f42b1209a156.tar.gz go-tangerine-1bdde620dad3c5fccb8e5de19fe7f42b1209a156.tar.zst go-tangerine-1bdde620dad3c5fccb8e5de19fe7f42b1209a156.zip |
les: fix light fetcher database race (#16103)
* les: fix light fetcher database race
* les: lightFetcher comments
-rw-r--r-- | les/fetcher.go | 30 |
1 files changed, 21 insertions, 9 deletions
diff --git a/les/fetcher.go b/les/fetcher.go index 9d224176f..e12a2c78a 100644 --- a/les/fetcher.go +++ b/les/fetcher.go @@ -36,24 +36,26 @@ const ( 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 { pm *ProtocolManager odr *LesOdr chain *light.LightChain + lock sync.Mutex // lock protects access to the fetcher's internal state variables except sent requests maxConfirmedTd *big.Int peers map[*peer]*fetcherPeerInfo lastUpdateStats *updateStatsEntry + syncing bool + syncDone chan *peer - lock sync.Mutex // qwerqwerqwe - deliverChn chan fetchResponse - reqMu sync.RWMutex + reqMu sync.RWMutex // reqMu protects access to sent header fetch requests requested map[uint64]fetchRequest + deliverChn chan fetchResponse timeoutChn chan uint64 requestChn chan bool // true if initiated from outside - syncing bool - syncDone chan *peer } // fetcherPeerInfo holds fetcher-specific information about each active peer @@ -560,8 +562,13 @@ func (f *lightFetcher) checkAnnouncedHeaders(fp *fetcherPeerInfo, headers []*typ return true } // 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) - header = f.chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) + hash, number := 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 { header = headers[i] td = tds[i] @@ -645,13 +652,18 @@ func (f *lightFetcher) checkKnownNode(p *peer, n *fetcherTreeNode) bool { if td == nil { 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] if fp == nil { p.Log().Debug("Unknown peer to check known nodes") return false } - header := f.chain.GetHeader(n.hash, n.number) if !f.checkAnnouncedHeaders(fp, []*types.Header{header}, []*big.Int{td}) { p.Log().Debug("Inconsistent announcement") go f.pm.removePeer(p.id) |