Skip to content
This repository was archived by the owner on May 21, 2024. It is now read-only.

Commit fc01a7c

Browse files
authored
les/vflux/client, p2p/nodestate: fix data races (ethereum#24058)
Fixes ethereum#23848
1 parent 155795b commit fc01a7c

File tree

2 files changed

+42
-6
lines changed

2 files changed

+42
-6
lines changed

les/vflux/client/serverpool_test.go

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ type ServerPoolTest struct {
6363
trusted []string
6464
waitCount, waitEnded int32
6565

66-
lock sync.Mutex
66+
// preNegLock protects the cycle counter, testNodes list and its connected field
67+
// (accessed from both the main thread and the preNeg callback)
68+
preNegLock sync.Mutex
69+
queryWg *sync.WaitGroup // a new wait group is created each time the simulation is started
70+
stopping bool // stopping avoid callind queryWg.Add after queryWg.Wait
6771

6872
cycle, conn, servedConn int
6973
serviceCycles, dialCount int
@@ -111,13 +115,21 @@ func (s *ServerPoolTest) addTrusted(i int) {
111115

112116
func (s *ServerPoolTest) start() {
113117
var testQuery QueryFunc
118+
s.queryWg = new(sync.WaitGroup)
114119
if s.preNeg {
115120
testQuery = func(node *enode.Node) int {
121+
s.preNegLock.Lock()
122+
if s.stopping {
123+
s.preNegLock.Unlock()
124+
return 0
125+
}
126+
s.queryWg.Add(1)
116127
idx := testNodeIndex(node.ID())
117128
n := &s.testNodes[idx]
118-
s.lock.Lock()
119129
canConnect := !n.connected && n.connectCycles != 0 && s.cycle >= n.nextConnCycle
120-
s.lock.Unlock()
130+
s.preNegLock.Unlock()
131+
defer s.queryWg.Done()
132+
121133
if s.preNegFail {
122134
// simulate a scenario where UDP queries never work
123135
s.beginWait()
@@ -181,11 +193,20 @@ func (s *ServerPoolTest) start() {
181193
}
182194

183195
func (s *ServerPoolTest) stop() {
196+
// disable further queries and wait if one is currently running
197+
s.preNegLock.Lock()
198+
s.stopping = true
199+
s.preNegLock.Unlock()
200+
s.queryWg.Wait()
201+
184202
quit := make(chan struct{})
185203
s.quit <- quit
186204
<-quit
187205
s.sp.Stop()
188206
s.spi.Close()
207+
s.preNegLock.Lock()
208+
s.stopping = false
209+
s.preNegLock.Unlock()
189210
for i := range s.testNodes {
190211
n := &s.testNodes[i]
191212
if n.connected {
@@ -205,7 +226,9 @@ func (s *ServerPoolTest) run() {
205226
n := &s.testNodes[idx]
206227
s.sp.UnregisterNode(n.node)
207228
n.totalConn += s.cycle
229+
s.preNegLock.Lock()
208230
n.connected = false
231+
s.preNegLock.Unlock()
209232
n.node = nil
210233
s.conn--
211234
if n.service {
@@ -230,7 +253,9 @@ func (s *ServerPoolTest) run() {
230253
s.servedConn++
231254
}
232255
n.totalConn -= s.cycle
256+
s.preNegLock.Lock()
233257
n.connected = true
258+
s.preNegLock.Unlock()
234259
dc := s.cycle + n.connectCycles
235260
s.disconnect[dc] = append(s.disconnect[dc], idx)
236261
n.node = dial
@@ -242,9 +267,9 @@ func (s *ServerPoolTest) run() {
242267
}
243268
s.serviceCycles += s.servedConn
244269
s.clock.Run(time.Second)
245-
s.lock.Lock()
270+
s.preNegLock.Lock()
246271
s.cycle++
247-
s.lock.Unlock()
272+
s.preNegLock.Unlock()
248273
}
249274
}
250275

@@ -255,11 +280,13 @@ func (s *ServerPoolTest) setNodes(count, conn, wait int, service, trusted bool)
255280
idx = rand.Intn(spTestNodes)
256281
}
257282
res = append(res, idx)
283+
s.preNegLock.Lock()
258284
s.testNodes[idx] = spTestNode{
259285
connectCycles: conn,
260286
waitCycles: wait,
261287
service: service,
262288
}
289+
s.preNegLock.Unlock()
263290
if trusted {
264291
s.addTrusted(idx)
265292
}
@@ -273,7 +300,9 @@ func (s *ServerPoolTest) resetNodes() {
273300
n.totalConn += s.cycle
274301
s.sp.UnregisterNode(n.node)
275302
}
303+
s.preNegLock.Lock()
276304
s.testNodes[i] = spTestNode{totalConn: n.totalConn}
305+
s.preNegLock.Unlock()
277306
}
278307
s.conn, s.servedConn = 0, 0
279308
s.disconnect = make(map[int][]int)

p2p/nodestate/nodestate.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,14 @@ func (ns *NodeStateMachine) addTimeout(n *enode.Node, mask bitMask, timeout time
808808
ns.removeTimeouts(node, mask)
809809
t := &nodeStateTimeout{mask: mask}
810810
t.timer = ns.clock.AfterFunc(timeout, func() {
811-
ns.SetState(n, Flags{}, Flags{mask: t.mask, setup: ns.setup}, 0)
811+
ns.lock.Lock()
812+
defer ns.lock.Unlock()
813+
814+
if !ns.opStart() {
815+
return
816+
}
817+
ns.setState(n, Flags{}, Flags{mask: t.mask, setup: ns.setup}, 0)
818+
ns.opFinish()
812819
})
813820
node.timeouts = append(node.timeouts, t)
814821
if mask&ns.saveFlags != 0 {

0 commit comments

Comments
 (0)