consensus: implement DeepCopy() in PoolObj, close XFN-04 (#1723)

* add DeepCopy() for PoolObj

* PoolObj: use deepcopies and optimize locks

* optimize code
This commit is contained in:
Wanwiset Peerapatanapokin 2025-11-10 21:56:10 +04:00 committed by GitHub
parent 845137849d
commit 7aaa541db1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 90 additions and 6 deletions

View file

@ -10,6 +10,7 @@ type PoolObj interface {
Hash() common.Hash
PoolKey() string
GetSigner() common.Address
DeepCopy() interface{}
}
type Pool struct {
objList map[string]map[common.Hash]PoolObj
@ -22,7 +23,17 @@ func NewPool() *Pool {
}
}
func (p *Pool) Get() map[string]map[common.Hash]PoolObj {
return p.objList
p.lock.RLock()
defer p.lock.RUnlock()
dataCopy := make(map[string]map[common.Hash]PoolObj, len(p.objList))
for k1, v1 := range p.objList {
dataCopy[k1] = make(map[common.Hash]PoolObj, len(v1))
for k2, v2 := range v1 {
dataCopy[k1][k2] = v2.DeepCopy().(PoolObj)
}
}
return dataCopy
}
func (p *Pool) Add(obj PoolObj) (int, map[common.Hash]PoolObj) {
@ -36,10 +47,18 @@ func (p *Pool) Add(obj PoolObj) (int, map[common.Hash]PoolObj) {
}
objListKeyed[obj.Hash()] = obj
numOfItems := len(objListKeyed)
return numOfItems, objListKeyed
dataCopy := make(map[common.Hash]PoolObj, len(objListKeyed))
for k, v := range objListKeyed {
dataCopy[k] = v.DeepCopy().(PoolObj)
}
return numOfItems, dataCopy
}
func (p *Pool) Size(obj PoolObj) int {
p.lock.RLock()
defer p.lock.RUnlock()
poolKey := obj.PoolKey()
objListKeyed, ok := p.objList[poolKey]
if !ok {
@ -84,8 +103,8 @@ func (p *Pool) Clear() {
}
func (p *Pool) GetObjsByKey(poolKey string) []PoolObj {
p.lock.Lock()
defer p.lock.Unlock()
p.lock.RLock()
defer p.lock.RUnlock()
objListKeyed, ok := p.objList[poolKey]
if !ok {
@ -94,8 +113,8 @@ func (p *Pool) GetObjsByKey(poolKey string) []PoolObj {
objList := make([]PoolObj, len(objListKeyed))
cnt := 0
for _, obj := range objListKeyed {
objList[cnt] = obj
cnt += 1
objList[cnt] = obj.DeepCopy().(PoolObj)
cnt++
}
return objList
}

View file

@ -12,6 +12,12 @@ import (
type Round uint64
type Signature []byte
func (s Signature) DeepCopy() interface{} {
cpy := make([]byte, len(s))
copy(cpy, s)
return s
}
// Block Info struct in XDPoS 2.0, used for vote message, etc.
type BlockInfo struct {
Hash common.Hash `json:"hash"`
@ -27,6 +33,20 @@ type Vote struct {
GapNumber uint64 `json:"gapNumber"`
}
func (v *Vote) DeepCopy() interface{} {
proposedBlockInfoCopy := &BlockInfo{
Hash: v.ProposedBlockInfo.Hash,
Round: v.ProposedBlockInfo.Round,
Number: new(big.Int).Set(v.ProposedBlockInfo.Number),
}
return &Vote{
signer: v.signer,
ProposedBlockInfo: proposedBlockInfoCopy,
Signature: v.Signature.DeepCopy().(Signature),
GapNumber: v.GapNumber,
}
}
func (v *Vote) Hash() common.Hash {
return rlpHash(v)
}
@ -52,6 +72,15 @@ type Timeout struct {
GapNumber uint64
}
func (t *Timeout) DeepCopy() interface{} {
return &Timeout{
signer: t.signer,
Round: t.Round,
Signature: t.Signature.DeepCopy().(Signature),
GapNumber: t.GapNumber,
}
}
func (t *Timeout) Hash() common.Hash {
return rlpHash(t)
}
@ -75,6 +104,42 @@ type SyncInfo struct {
HighestTimeoutCert *TimeoutCert
}
func (s *SyncInfo) DeepCopy() interface{} {
var highestQCCopy *QuorumCert
if s.HighestQuorumCert != nil {
sigsCopy := make([]Signature, len(s.HighestQuorumCert.Signatures))
for i, sig := range s.HighestQuorumCert.Signatures {
sigsCopy[i] = sig.DeepCopy().(Signature)
}
highestQCCopy = &QuorumCert{
ProposedBlockInfo: &BlockInfo{
Hash: s.HighestQuorumCert.ProposedBlockInfo.Hash,
Round: s.HighestQuorumCert.ProposedBlockInfo.Round,
Number: new(big.Int).Set(s.HighestQuorumCert.ProposedBlockInfo.Number),
},
Signatures: sigsCopy,
GapNumber: s.HighestQuorumCert.GapNumber,
}
}
var highestTimeoutCopy *TimeoutCert
if s.HighestTimeoutCert != nil {
sigsCopy := make([]Signature, len(s.HighestTimeoutCert.Signatures))
for i, sig := range s.HighestTimeoutCert.Signatures {
sigsCopy[i] = sig.DeepCopy().(Signature)
}
highestTimeoutCopy = &TimeoutCert{
Round: s.HighestTimeoutCert.Round,
Signatures: sigsCopy,
GapNumber: s.HighestTimeoutCert.GapNumber,
}
}
return &SyncInfo{
HighestQuorumCert: highestQCCopy,
HighestTimeoutCert: highestTimeoutCopy,
}
}
func (s *SyncInfo) Hash() common.Hash {
return rlpHash(s)
}