Here are changes for fixing the racing problems.
1. segmentmerkle.go remove all uses of segments_merkle_mutex RLock() and
RUnlock(), toplevel callers will have to lock that
instead.
code omitted2. anonminize.go, add 2 mutexes rlock and runlock around segments_coinbase_backgraph:
for combbase := range bases {
segments_transaction_mutex.RLock()
segments_merkle_mutex.RLock()
segments_coinbase_backgraph(backgraph, make(map[[32]byte]struct{}), target, combbase)
segments_merkle_mutex.RUnlock()
segments_transaction_mutex.RUnlock()
}
3. loopdetect.go, add 2 mutexes rlock and runlock to loopdetect() function:
func loopdetect(norecursion, loopkiller map[[32]byte]struct{}, to [32]byte) (b bool) {
segments_transaction_mutex.RLock()
segments_merkle_mutex.RLock()
var type3 = segments_stack_type(to)
if type3 == SEGMENT_STACK_TRICKLED {
b = segments_stack_loopdetect(norecursion, loopkiller, to)
}
var type2 = segments_merkle_type(to)
if type2 == SEGMENT_MERKLE_TRICKLED {
b = segments_merkle_loopdetect(norecursion, loopkiller, to)
}
var type1 = segments_transaction_type(to)
if type1 == SEGMENT_TX_TRICKLED {
b = segments_transaction_loopdetect(norecursion, loopkiller, to)
} else if type1 == SEGMENT_ANY_UNTRICKLED {
} else if type1 == SEGMENT_UNKNOWN {
}
segments_merkle_mutex.RUnlock()
segments_transaction_mutex.RUnlock()
return b
}
4. merkle.go commits mutex MUST be taken when call merkle_scan_one_leg_activity() here:
commits_mutex.RLock()
var allright1 = merkle_scan_one_leg_activity(q1)
var allright2 = merkle_scan_one_leg_activity(q2)
if allright1 && allright2 {
reactivate_txid(false, true, tx)
}
commits_mutex.RUnlock()
return true, e[0]
and add 2 mutexes rlock and runlock:
if newactivity {
segments_transaction_mutex.Lock()
segments_merkle_mutex.Lock()
if old, ok1 := e0_to_e1[e[0]]; ok1 && old != e[1] {
fmt.Println("Panic: e0 to e1 already have live path")
panic("")
}
e0_to_e1[e[0]] = e[1]
segments_merkle_mutex.Unlock()
segments_transaction_mutex.Unlock()
segments_transaction_mutex.RLock()
segments_merkle_mutex.RLock()
var maybecoinbase = commit(e[0][0:])
if _, ok1 := combbases[maybecoinbase]; ok1 {
segments_coinbase_trickle_auto(maybecoinbase, e[0])
}
segments_merkle_trickle(make(map[[32]byte]struct{}), e[0])
segments_merkle_mutex.RUnlock()
segments_transaction_mutex.RUnlock()
}
5. mine.go add write locking:
if *tx == (*txidto)[0] {
segments_transaction_mutex.Lock()
segments_transaction_next[actuallyfrom] = *txidto
segments_transaction_mutex.Unlock()
return false
}
change 2 add toplevel locking:
segments_transaction_mutex.RLock()
segments_merkle_mutex.RLock()
var maybecoinbase = commit(actuallyfrom[0:])
if _, ok1 := combbases[maybecoinbase]; ok1 {
segments_coinbase_trickle_auto(maybecoinbase, actuallyfrom)
}
segments_transaction_trickle(make(map[[32]byte]struct{}), actuallyfrom)
segments_merkle_mutex.RUnlock()
segments_transaction_mutex.RUnlock()
change 3:
segments_transaction_mutex.RLock()
var val = segments_transaction_data[*tx][i]
segments_transaction_mutex.RUnlock()
change 4:
if oldactivity == 2097151 {
segments_transaction_mutex.Lock()
var actuallyfrom = segments_transaction_data[*tx][21]
segments_transaction_untrickle(nil, actuallyfrom, 0xffffffffffffffff)
delete(segments_transaction_next, actuallyfrom)
segments_transaction_mutex.Unlock()
}
6. stack.go surround stack trickle with mutexes:
segments_transaction_mutex.RLock()
segments_merkle_mutex.RLock()
segments_stack_trickle(make(map[[32]byte]struct{}), hash)
segments_merkle_mutex.RUnlock()
segments_transaction_mutex.RUnlock()
7. txrecv.go tx_receive_transaction_internal(), take both mutexes:
segments_transaction_mutex.Lock()
segments_merkle_mutex.Lock()
and
segments_merkle_mutex.Unlock()
segments_transaction_mutex.Unlock()