Add seed node#45
Open
crappyrules wants to merge 2 commits intoblocknetprivacy:masterfrom
Open
Conversation
… under the write lock
Root cause
----------
The blocknet-core binary could crash with
fatal error: concurrent map read and map write
in goroutines reaching (*Chain).nextDifficultyLocked via TemplateParams.
TemplateParams held only c.mu.RLock while reading c.blocks and c.byHeight,
but several "*Locked" helpers transitively reachable from other RLock
holders were actually mutating chain state:
* getBlockByHashLocked wrote to c.blocks and mutated the LRU cache on
storage-fallback.
* ensureCanonicalRingIndexLocked rebuilt c.canonicalRingIndex /
c.canonicalRingHeights and set c.canonicalRingIndexTip /
.Ready / .Dirty, and invoked getBlockByHashLocked internally.
* isCanonicalRingMemberLocked (called from IsCanonicalRingMember and
SelectRingMembersWithCommitments under RLock) invoked
ensureCanonicalRingIndexLocked, so two concurrent RLock holders
could write the same maps while another RLock reader
(TemplateParams/nextDifficultyLocked) was iterating them.
Because sync.RWMutex.RLock permits multiple concurrent readers, any
mutation performed under RLock races with every other RLock-holding
reader. The Go runtime detects read+write on a map and aborts the
process.
Fix
---
Every mutation of shared chain maps (c.blocks, c.byHeight,
c.canonicalRingIndex, c.canonicalRingHeights, cache LRU/index) now
runs only under c.mu.Lock (the write lock). Read-only callers that
hold only c.mu.RLock never mutate state.
Changes in block.go:
1. loadFromStorage now eagerly builds the canonical ring-member index
before returning. This happens while NewChain is still
single-threaded, so no other goroutine can hold c.mu. After startup
canonicalRingIndexReady=true and canonicalRingIndexDirty=false, and
updateCanonicalRingIndexForConnect / updateCanonicalRingIndexForDisconnect
keep it in sync incrementally from write-lock-only paths
(addBlockInternal, reorganizeTo).
2. TruncateToHeight now calls ensureCanonicalRingIndexLocked after its
in-memory mutations, while still holding the write lock, so readers
never observe a dirty index.
3. isCanonicalRingMemberLocked is now a pure read. It no longer calls
ensureCanonicalRingIndexLocked. A not-ready index returns false;
callers that need guaranteed freshness must call
ensureCanonicalRingIndexLocked themselves under the write lock
(branchAwareRingMemberCheckerLocked already does this).
4. IsCanonicalRingMember gained an RLock fast path and a write-lock
escalation slow path:
- RLock + pre-built index lookup when the index is usable.
- If the index is not ready, is dirty, or out of sync with the
persisted tip, release RLock, acquire Lock, rebuild the index,
then answer.
5. SelectRingMembersWithCommitments got the same RLock / write-lock
escalation. The shuffle + ring assembly tail was extracted into
the new pure-function helper finalizeRingSelection so the fast path
can release c.mu before doing CPU-bound work.
6. Added helper canonicalRingMemberIndexUsableRLocked to decide
fast vs slow path without mutating state.
7. Added lock-requirement doc comments to getBlockByHashLocked,
ensureCanonicalRingIndexLocked, and isCanonicalRingMemberLocked
so future callers can tell which lock they need to hold.
Verification
------------
* `go build ./...` clean.
* `go vet ./...` clean.
* `go test -race -count=1 blocknet` passes (previously flagged the
same maps under concurrent access).
* Existing tests that reference chain.getBlockByHashLocked /
chain.isCanonicalRingMemberLocked (block_branch_ringmember_test.go,
chain_cache_bounds_test.go) continue to pass; they already call
these helpers under chain.mu.Lock, which matches the documented
requirement.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
adding additional seed node to seed_resolve.go
adding additional lock-fixes to resolve node crashes.