Skip to content

Commit f1edca9

Browse files
committed
Prevent subtree data race
1 parent 17f17c2 commit f1edca9

File tree

1 file changed

+28
-8
lines changed

1 file changed

+28
-8
lines changed

services/blockassembly/subtreeprocessor/SubtreeProcessor.go

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ type SubtreeProcessor struct {
209209
// currentSubtree represents the subtree currently being built
210210
currentSubtree *subtreepkg.Subtree
211211

212+
// currentSubtreeMu protects currentSubtree pointer from concurrent read/write access
213+
currentSubtreeMu sync.RWMutex
214+
212215
// currentBlockHeader stores the current block header being processed
213216
currentBlockHeader *model.BlockHeader
214217

@@ -567,7 +570,7 @@ func (stp *SubtreeProcessor) Start(ctx context.Context) {
567570
if _, err = stp.moveForwardBlock(processorCtx, moveForwardReq.block, false, processedConflictingHashesMap, false, true); err != nil {
568571
// rollback to previous state
569572
stp.chainedSubtrees = originalChainedSubtrees
570-
stp.currentSubtree = originalCurrentSubtree
573+
stp.setCurrentSubtree(originalCurrentSubtree)
571574
stp.currentTxMap = originalCurrentTxMap
572575
stp.currentBlockHeader = currentBlockHeader
573576

@@ -827,7 +830,8 @@ func (stp *SubtreeProcessor) reset(blockHeader *model.BlockHeader, moveBackBlock
827830
stp.chainedSubtrees = make([]*subtreepkg.Subtree, 0, ExpectedNumberOfSubtrees)
828831
stp.chainedSubtreeCount.Store(0)
829832

830-
stp.currentSubtree, _ = subtreepkg.NewTreeByLeafCount(stp.currentItemsPerFile)
833+
newSubtree, _ := subtreepkg.NewTreeByLeafCount(stp.currentItemsPerFile)
834+
stp.setCurrentSubtree(newSubtree)
831835
if err := stp.currentSubtree.AddCoinbaseNode(); err != nil {
832836
return errors.NewProcessingError("[SubtreeProcessor][Reset] error adding coinbase placeholder to new current subtree", err)
833837
}
@@ -1041,11 +1045,22 @@ func (stp *SubtreeProcessor) SetCurrentBlockHeader(blockHeader *model.BlockHeade
10411045
stp.currentBlockHeader = blockHeader
10421046
}
10431047

1048+
// setCurrentSubtree safely updates the currentSubtree pointer with write lock protection.
1049+
// This is used internally to prevent data races when external callers read via GetCurrentSubtree().
1050+
func (stp *SubtreeProcessor) setCurrentSubtree(st *subtreepkg.Subtree) {
1051+
stp.currentSubtreeMu.Lock()
1052+
stp.currentSubtree = st
1053+
stp.currentSubtreeMu.Unlock()
1054+
}
1055+
10441056
// GetCurrentSubtree returns the subtree currently being built.
1057+
// This method is safe for concurrent access from external callers.
10451058
//
10461059
// Returns:
10471060
// - *util.Subtree: Current subtree
10481061
func (stp *SubtreeProcessor) GetCurrentSubtree() *subtreepkg.Subtree {
1062+
stp.currentSubtreeMu.RLock()
1063+
defer stp.currentSubtreeMu.RUnlock()
10491064
return stp.currentSubtree
10501065
}
10511066

@@ -1349,10 +1364,11 @@ func (stp *SubtreeProcessor) addNode(node subtreepkg.Node, parents *subtreepkg.T
13491364
}
13501365

13511366
if stp.currentSubtree == nil {
1352-
stp.currentSubtree, err = subtreepkg.NewTreeByLeafCount(stp.currentItemsPerFile)
1367+
newSubtree, err := subtreepkg.NewTreeByLeafCount(stp.currentItemsPerFile)
13531368
if err != nil {
13541369
return err
13551370
}
1371+
stp.setCurrentSubtree(newSubtree)
13561372

13571373
// This is the first subtree for this block - we need a coinbase placeholder
13581374
err = stp.currentSubtree.AddCoinbaseNode()
@@ -1404,10 +1420,11 @@ func (stp *SubtreeProcessor) processCompleteSubtree(skipNotification bool) (err
14041420
oldSubtreeHash := oldSubtree.RootHash()
14051421

14061422
// create a new subtree with the same height as the previous subtree
1407-
stp.currentSubtree, err = subtreepkg.NewTree(stp.currentSubtree.Height)
1423+
newSubtree, err := subtreepkg.NewTree(oldSubtree.Height)
14081424
if err != nil {
14091425
return errors.NewProcessingError("[%s] error creating new subtree", oldSubtreeHash.String(), err)
14101426
}
1427+
stp.setCurrentSubtree(newSubtree)
14111428

14121429
// Send the subtree to the newSubtreeChan, including a reference to the parent transactions map
14131430
errCh := make(chan error)
@@ -1637,10 +1654,11 @@ func (stp *SubtreeProcessor) reChainSubtrees(fromIndex int) error {
16371654

16381655
stp.chainedSubtreeCount.Store(fromIndexInt32)
16391656

1640-
stp.currentSubtree, err = subtreepkg.NewTreeByLeafCount(stp.currentItemsPerFile)
1657+
newSubtree, err := subtreepkg.NewTreeByLeafCount(stp.currentItemsPerFile)
16411658
if err != nil {
16421659
return errors.NewProcessingError("error creating new current subtree", err)
16431660
}
1661+
stp.setCurrentSubtree(newSubtree)
16441662

16451663
if len(originalSubtrees) == 0 {
16461664
// we must add the coinbase tx if we have no original subtrees
@@ -1888,7 +1906,7 @@ func (stp *SubtreeProcessor) reorgBlocks(ctx context.Context, moveBackBlocks []*
18881906
if err != nil {
18891907
// restore the original state
18901908
stp.chainedSubtrees = originalChainedSubtrees
1891-
stp.currentSubtree = originalCurrentSubtree
1909+
stp.setCurrentSubtree(originalCurrentSubtree)
18921910
stp.currentTxMap = originalCurrentTxMap
18931911
stp.currentBlockHeader = currentBlockHeader
18941912

@@ -2308,10 +2326,11 @@ func (stp *SubtreeProcessor) moveBackBlockCreateNewSubtrees(ctx context.Context,
23082326
// we create as few subtrees as possible when moving back, to avoid fragmentation and lots of small writes to disk
23092327
subtreeSize = 1024 * 1024
23102328
}
2311-
stp.currentSubtree, err = subtreepkg.NewTreeByLeafCount(subtreeSize)
2329+
newSubtree, err := subtreepkg.NewTreeByLeafCount(subtreeSize)
23122330
if err != nil {
23132331
return nil, nil, errors.NewProcessingError("[moveBackBlock:CreateNewSubtrees][%s] error creating new subtree", block.String(), err)
23142332
}
2333+
stp.setCurrentSubtree(newSubtree)
23152334

23162335
stp.chainedSubtrees = make([]*subtreepkg.Subtree, 0, ExpectedNumberOfSubtrees)
23172336
stp.chainedSubtreeCount.Store(0)
@@ -2576,10 +2595,11 @@ func (stp *SubtreeProcessor) resetSubtreeState(createProperlySizedSubtrees bool)
25762595
subtreeSize = 1024 * 1024
25772596
}
25782597

2579-
stp.currentSubtree, err = subtreepkg.NewTreeByLeafCount(subtreeSize)
2598+
newSubtree, err := subtreepkg.NewTreeByLeafCount(subtreeSize)
25802599
if err != nil {
25812600
return err
25822601
}
2602+
stp.setCurrentSubtree(newSubtree)
25832603

25842604
stp.chainedSubtrees = make([]*subtreepkg.Subtree, 0, ExpectedNumberOfSubtrees)
25852605
stp.chainedSubtreeCount.Store(0)

0 commit comments

Comments
 (0)