fix(consensus): fix config object not reference to same one and concurrency issues and refactor access pattern (#2146)

* bug fix for using same config object

* update

* change log level to trace on ispochswtich

---------

Co-authored-by: liam.lai <liam.lai@babylonchain.io>
This commit is contained in:
benjamin202410 2026-03-12 12:12:49 -07:00 committed by GitHub
parent c762053cd6
commit be36b32b3e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 26 additions and 10 deletions

View file

@ -1,6 +1,7 @@
package engine_v2 package engine_v2
import ( import (
"bytes"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -1115,8 +1116,6 @@ func (x *XDPoS_v2) saveRewardToFile(blockHash common.Hash, blockNumber uint64) {
log.Debug("[saveRewardToFile] Saved rewards", "filename", filename) log.Debug("[saveRewardToFile] Saved rewards", "filename", filename)
log.Debug("[saveRewardToFile] Saved rewards", "rewards", string(data)) log.Debug("[saveRewardToFile] Saved rewards", "rewards", string(data))
return
} }
func deepCloneJSON(original map[string]interface{}) (map[string]interface{}, error) { func deepCloneJSON(original map[string]interface{}) (map[string]interface{}, error) {
@ -1126,10 +1125,15 @@ func deepCloneJSON(original map[string]interface{}) (map[string]interface{}, err
} }
var cloned map[string]interface{} var cloned map[string]interface{}
err = json.Unmarshal(data, &cloned) dec := json.NewDecoder(bytes.NewReader(data))
if err != nil { dec.UseNumber()
if err = dec.Decode(&cloned); err != nil {
return nil, fmt.Errorf("failed to unmarshal: %w", err) return nil, fmt.Errorf("failed to unmarshal: %w", err)
} }
return cloned, nil return cloned, nil
} }
func (x *XDPoS_v2) Config(r uint64) *params.V2Config {
return x.config.V2.Config(r)
}

View file

@ -164,7 +164,7 @@ func (x *XDPoS_v2) IsEpochSwitch(header *types.Header) (bool, uint64, error) {
log.Info("[IsEpochSwitch] true, parent equals V2.SwitchBlock", "round", round, "number", header.Number.Uint64(), "hash", header.Hash()) log.Info("[IsEpochSwitch] true, parent equals V2.SwitchBlock", "round", round, "number", header.Number.Uint64(), "hash", header.Hash())
return true, epochNum, nil return true, epochNum, nil
} }
log.Debug("[IsEpochSwitch]", "is", parentRound < epochStartRound, "parentRound", parentRound, "round", round, "number", header.Number.Uint64(), "epochNum", epochNum, "hash", header.Hash().Hex()) log.Trace("[IsEpochSwitch]", "is", parentRound < epochStartRound, "parentRound", parentRound, "round", round, "number", header.Number.Uint64(), "epochNum", epochNum, "hash", header.Hash().Hex())
// if isEpochSwitch, add to cache // if isEpochSwitch, add to cache
if parentRound < epochStartRound { if parentRound < epochStartRound {
x.round2epochBlockInfo.Add(round, &types.BlockInfo{ x.round2epochBlockInfo.Add(round, &types.BlockInfo{

View file

@ -99,7 +99,8 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf
listBlockHash = append(listBlockHash, parentHash) listBlockHash = append(listBlockHash, parentHash)
} }
currentConfig := chain.Config().XDPoS.V2.Config(uint64(round)) currentConfig := adaptor.EngineV2.Config(uint64(round))
// add list not miner to penalties // add list not miner to penalties
preMasternodes := adaptor.EngineV2.GetMasternodesByHash(chain, currentHash) preMasternodes := adaptor.EngineV2.GetMasternodesByHash(chain, currentHash)
penalties := []common.Address{} penalties := []common.Address{}
@ -286,7 +287,9 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf
log.Error("[HookReward] Fail to get round", "error", err) log.Error("[HookReward] Fail to get round", "error", err)
return nil, err return nil, err
} }
currentConfig := chain.Config().XDPoS.V2.Config(uint64(round))
currentConfig := adaptor.EngineV2.Config(uint64(round))
// Get signers/signing tx count, and burned tokens in one epoch // Get signers/signing tx count, and burned tokens in one epoch
signers, burnedInOneEpoch, err := GetSigningTxCount(adaptor, chain, header, parentState, currentConfig) signers, burnedInOneEpoch, err := GetSigningTxCount(adaptor, chain, header, parentState, currentConfig)

View file

@ -840,11 +840,14 @@ func (v2 *V2) GetCurrentConfig() *V2Config {
} }
// avoid CurrentConfig is changed by other goroutines // avoid CurrentConfig is changed by other goroutines
cpyConfig := *v2.CurrentConfig cfg := *v2.CurrentConfig
return &cpyConfig return &cfg
} }
func (v2 *V2) Config(round uint64) *V2Config { func (v2 *V2) Config(round uint64) *V2Config {
v2.lock.RLock()
defer v2.lock.RUnlock()
configRound := round configRound := round
var index uint64 var index uint64
@ -855,10 +858,16 @@ func (v2 *V2) Config(round uint64) *V2Config {
break break
} }
} }
return v2.AllConfigs[index]
// avoid config is changed by other goroutines
cfg := *v2.AllConfigs[index]
return &cfg
} }
func (v2 *V2) BuildConfigIndex() { func (v2 *V2) BuildConfigIndex() {
v2.lock.Lock()
defer v2.lock.Unlock()
list := slices.Collect(maps.Keys(v2.AllConfigs)) list := slices.Collect(maps.Keys(v2.AllConfigs))
// Make it descending order // Make it descending order
slices.SortFunc(list, func(a, b uint64) int { slices.SortFunc(list, func(a, b uint64) int {