From c5b303ed860f32351c8207bf925f1fa9ffc7f9f9 Mon Sep 17 00:00:00 2001 From: Alex Sharov Date: Wed, 23 Oct 2024 16:22:05 +0700 Subject: [PATCH] bor: milestone avoid `TryLock` (#12422) `TryLock` - tells that mutex was locked - but doesn't tell by whom. maybe by parent caller, maybe by another goroutine. So next pattern is bad: ``` if m.finality.TryLock() { defer m.finality.Unlock() } // mutate ``` because mutex can be locked by another goroutine and our func will mutate fields without waiting for mutex. ``` ================== WARNING: DATA RACE Write at 0x00c004e64688 by goroutine 28583: github.com/erigontech/erigon/polygon/bor/finality/whitelist.(*milestone).UnlockSprint() github.com/erigontech/erigon/polygon/bor/finality/whitelist/milestone.go:175 +0x106 github.com/erigontech/erigon/polygon/bor/finality.fetchWhitelistMilestone() github.com/erigontech/erigon/polygon/bor/finality/whitelist_helpers.go:113 +0xb3b github.com/erigontech/erigon/polygon/bor/finality.handleMilestone() github.com/erigontech/erigon/polygon/bor/finality/whitelist.go:202 +0xc8 github.com/erigontech/erigon/polygon/bor/finality.retryHeimdallHandler() github.com/erigontech/erigon/polygon/bor/finality/whitelist.go:159 +0x5cb github.com/erigontech/erigon/polygon/bor/finality.RetryHeimdallHandler() github.com/erigontech/erigon/polygon/bor/finality/whitelist.go:117 +0x5c github.com/erigontech/erigon/polygon/bor/finality.startMilestoneWhitelistService() github.com/erigontech/erigon/polygon/bor/finality/whitelist.go:93 +0x2a github.com/erigontech/erigon/polygon/bor/finality.Whitelist.gowrap2() github.com/erigontech/erigon/polygon/bor/finality/whitelist.go:64 +0x17 Previous write at 0x00c004e64688 by goroutine 28584: github.com/erigontech/erigon/polygon/bor/finality/whitelist.(*milestone).RemoveMilestoneID() github.com/erigontech/erigon/polygon/bor/finality/whitelist/milestone.go:194 +0x164 github.com/erigontech/erigon/polygon/bor/finality.handleNoAckMilestone() github.com/erigontech/erigon/polygon/bor/finality/whitelist.go:237 +0x12c github.com/erigontech/erigon/polygon/bor/finality.retryHeimdallHandler() github.com/erigontech/erigon/polygon/bor/finality/whitelist.go:159 +0x5cb github.com/erigontech/erigon/polygon/bor/finality.RetryHeimdallHandler() github.com/erigontech/erigon/polygon/bor/finality/whitelist.go:117 +0x57 github.com/erigontech/erigon/polygon/bor/finality.startNoAckMilestoneService() github.com/erigontech/erigon/polygon/bor/finality/whitelist.go:102 +0x2a github.com/erigontech/erigon/polygon/bor/finality.Whitelist.gowrap3() github.com/erigontech/erigon/polygon/bor/finality/whitelist.go:65 +0x17 ``` --- polygon/bor/finality/whitelist/milestone.go | 22 +++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/polygon/bor/finality/whitelist/milestone.go b/polygon/bor/finality/whitelist/milestone.go index 2fbb1f735b5..ce56b70f97a 100644 --- a/polygon/bor/finality/whitelist/milestone.go +++ b/polygon/bor/finality/whitelist/milestone.go @@ -120,7 +120,7 @@ func (m *milestone) Process(block uint64, hash common.Hash) { whitelistedMilestoneMeter.SetUint64(block) - m.UnlockSprint(block) + m.unlockSprint(block) } // LockMutex This function will Lock the mutex at the time of voting @@ -145,7 +145,7 @@ func (m *milestone) UnlockMutex(doLock bool, milestoneId string, endBlockNum uin m.Locked = m.Locked || doLock if doLock { - m.UnlockSprint(m.LockedMilestoneNumber) + m.unlockSprint(m.LockedMilestoneNumber) m.Locked = true m.LockedMilestoneHash = endBlockHash m.LockedMilestoneNumber = endBlockNum @@ -168,8 +168,16 @@ func (m *milestone) UnlockSprint(endBlockNum uint64) { return } - if m.finality.TryLock() { - defer m.finality.Unlock() + m.finality.Lock() + defer m.finality.Unlock() + + m.unlockSprint(endBlockNum) +} + +// UnlockSprint This function will unlock the locked sprint +func (m *milestone) unlockSprint(endBlockNum uint64) { + if endBlockNum < m.LockedMilestoneNumber { + return } m.Locked = false @@ -233,12 +241,6 @@ func (m *milestone) GetMilestoneIDsList() []string { // This is remove the milestoneIDs stored in the list. func (m *milestone) purgeMilestoneIDsList() { - // try is used here as the finality lock is preserved over calls - so the lock state - // is not clearly defined in the local code - this likely needs to be revised - if m.finality.TryLock() { - defer m.finality.Unlock() - } - m.LockedMilestoneIDs = make(map[string]struct{}) }