les: fix light fetcher database race (#16103)
* les: fix light fetcher database race * les: lightFetcher comments
This commit is contained in:
		
				
					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)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user