xin-153 Broadcast syncInfo when consecutive timeouts of same round (#65)

* Broadcast syncInfo when consecutive timeouts of same round

* add test

* revert test period
This commit is contained in:
Liam 2022-03-05 01:52:20 +01:00 committed by GitHub
parent e493ddfd6d
commit d975ba4014
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 22 deletions

View file

@ -45,6 +45,7 @@ type XDPoS_v2 struct {
waitPeriodCh chan int waitPeriodCh chan int
timeoutWorker *countdown.CountdownTimer // Timer to generate broadcast timeout msg if threashold reached timeoutWorker *countdown.CountdownTimer // Timer to generate broadcast timeout msg if threashold reached
timeoutCount int // number of timeout being sent
timeoutPool *utils.Pool timeoutPool *utils.Pool
votePool *utils.Pool votePool *utils.Pool
@ -62,7 +63,7 @@ type XDPoS_v2 struct {
func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) *XDPoS_v2 { func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) *XDPoS_v2 {
// Setup Timer // Setup Timer
duration := time.Duration(config.V2.TimeoutWorkerDuration) * time.Second duration := time.Duration(config.V2.TimeoutPeriod) * time.Second
timer := countdown.NewCountDown(duration) timer := countdown.NewCountDown(duration)
timeoutPool := utils.NewPool(config.V2.CertThreshold) timeoutPool := utils.NewPool(config.V2.CertThreshold)
@ -162,7 +163,7 @@ func (x *XDPoS_v2) Initial(chain consensus.ChainReader, masternodes []common.Add
} }
// Initial timeout // Initial timeout
log.Info("[Initial] miner wait period", "period", x.config.WaitPeriod) log.Info("[Initial] miner wait period", "period", x.config.V2.WaitPeriod)
// avoid deadlock // avoid deadlock
go func() { go func() {
x.waitPeriodCh <- x.config.V2.WaitPeriod x.waitPeriodCh <- x.config.V2.WaitPeriod
@ -1184,6 +1185,7 @@ func (x *XDPoS_v2) processTC(blockChainReader consensus.ChainReader, timeoutCert
*/ */
func (x *XDPoS_v2) setNewRound(blockChainReader consensus.ChainReader, round utils.Round) error { func (x *XDPoS_v2) setNewRound(blockChainReader consensus.ChainReader, round utils.Round) error {
x.currentRound = round x.currentRound = round
x.timeoutCount = 0
//TODO: tell miner now it's a new round and start mine if it's leader //TODO: tell miner now it's a new round and start mine if it's leader
x.timeoutWorker.Reset(blockChainReader) x.timeoutWorker.Reset(blockChainReader)
//TODO: vote pools //TODO: vote pools
@ -1352,6 +1354,14 @@ func (x *XDPoS_v2) OnCountdownTimeout(time time.Time, chain interface{}) error {
log.Error("Error while sending out timeout message at time: ", time) log.Error("Error while sending out timeout message at time: ", time)
return err return err
} }
x.timeoutCount++
if x.timeoutCount%x.config.V2.TimeoutSyncThreshold == 0 {
log.Info("[OnCountdownTimeout] timeout sync threadhold reached, send syncInfo message")
syncInfo := x.getSyncInfo()
x.broadcastToBftChannel(syncInfo)
}
return nil return nil
} }

View file

@ -1,11 +1,13 @@
package tests package tests
import ( import (
"fmt"
"testing" "testing"
"github.com/XinFinOrg/XDPoSChain/accounts" "github.com/XinFinOrg/XDPoSChain/accounts"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS" "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils" "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/params"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -19,9 +21,47 @@ func TestCountdownTimeoutToSendTimeoutMessage(t *testing.T) {
assert.Equal(t, poolSize, 1) assert.Equal(t, poolSize, 1)
assert.NotNil(t, timeoutMsg) assert.NotNil(t, timeoutMsg)
assert.Equal(t, uint64(1350), timeoutMsg.(*utils.Timeout).GapNumber) assert.Equal(t, uint64(1350), timeoutMsg.(*utils.Timeout).GapNumber)
fmt.Println(timeoutMsg.(*utils.Timeout).GapNumber)
assert.Equal(t, utils.Round(1), timeoutMsg.(*utils.Timeout).Round) assert.Equal(t, utils.Round(1), timeoutMsg.(*utils.Timeout).Round)
} }
func TestSyncInfoAfterReachTimeoutSnycThreadhold(t *testing.T) {
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 2251, params.TestXDPoSMockChainConfig, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
// Because messages are sending async and on random order, so use this way to test
var timeoutCounter, syncInfoCounter int
for i := 0; i < 3; i++ {
obj := <-engineV2.BroadcastCh
switch v := obj.(type) {
case *utils.Timeout:
timeoutCounter++
case *utils.SyncInfo:
syncInfoCounter++
default:
log.Error("Unknown message type received", "value", v)
}
}
assert.Equal(t, 2, timeoutCounter)
assert.Equal(t, 1, syncInfoCounter)
t.Log("waiting for another consecutive period")
// another consecutive period
for i := 0; i < 3; i++ {
obj := <-engineV2.BroadcastCh
switch v := obj.(type) {
case *utils.Timeout:
timeoutCounter++
case *utils.SyncInfo:
syncInfoCounter++
default:
log.Error("Unknown message type received", "value", v)
}
}
assert.Equal(t, 4, timeoutCounter)
assert.Equal(t, 2, syncInfoCounter)
}
// Timeout handler // Timeout handler
func TestTimeoutMessageHandlerSuccessfullyGenerateTCandSyncInfo(t *testing.T) { func TestTimeoutMessageHandlerSuccessfullyGenerateTCandSyncInfo(t *testing.T) {
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, params.TestXDPoSMockChainConfig, 0) blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, params.TestXDPoSMockChainConfig, 0)

View file

@ -36,23 +36,25 @@ var (
var ( var (
XDPoSV2Config = &V2{ XDPoSV2Config = &V2{
TimeoutWorkerDuration: 50, TimeoutPeriod: 50,
CertThreshold: common.MaxMasternodesV2*2/3 + 1, CertThreshold: common.MaxMasternodesV2*2/3 + 1,
} }
TestXDPoSV2Config = &V2{ TestXDPoSV2Config = &V2{
TimeoutWorkerDuration: 10, SwitchBlock: big.NewInt(900),
CertThreshold: 3, CertThreshold: 3,
WaitPeriod: 1, TimeoutSyncThreshold: 2,
MinePeriod: 2, TimeoutPeriod: 10,
SwitchBlock: big.NewInt(900), WaitPeriod: 1,
SkipV2Validation: true, MinePeriod: 2,
SkipV2Validation: true,
} }
DevnetXDPoSV2Config = &V2{ DevnetXDPoSV2Config = &V2{
SwitchBlock: big.NewInt(7218000), SwitchBlock: big.NewInt(7218000),
TimeoutWorkerDuration: 50, CertThreshold: 6,
CertThreshold: 6, TimeoutSyncThreshold: 5,
WaitPeriod: 2, TimeoutPeriod: 50,
MinePeriod: 10, WaitPeriod: 2,
MinePeriod: 10,
} }
// XDPoSChain mainnet config // XDPoSChain mainnet config
@ -202,18 +204,18 @@ type XDPoSConfig struct {
RewardCheckpoint uint64 `json:"rewardCheckpoint"` // Checkpoint block for calculate rewards. RewardCheckpoint uint64 `json:"rewardCheckpoint"` // Checkpoint block for calculate rewards.
Gap uint64 `json:"gap"` // Gap time preparing for the next epoch Gap uint64 `json:"gap"` // Gap time preparing for the next epoch
FoudationWalletAddr common.Address `json:"foudationWalletAddr"` // Foundation Address Wallet FoudationWalletAddr common.Address `json:"foudationWalletAddr"` // Foundation Address Wallet
WaitPeriod int `json:"waitPeriod"` // Miner wait period
SkipV1Validation bool //Skip Block Validation for testing purpose, V1 consensus only SkipV1Validation bool //Skip Block Validation for testing purpose, V1 consensus only
V2 *V2 `json:"v2"` V2 *V2 `json:"v2"`
} }
type V2 struct { type V2 struct {
WaitPeriod int `json:"waitPeriod"` // Miner wait period to check mine event WaitPeriod int `json:"waitPeriod"` // Miner wait period to check mine event
MinePeriod int `json:"minePeriod"` // Miner mine period to mine a block MinePeriod int `json:"minePeriod"` // Miner mine period to mine a block
SwitchBlock *big.Int `json:"switchBlock"` // v1 to v2 switch block number SwitchBlock *big.Int `json:"switchBlock"` // v1 to v2 switch block number
TimeoutWorkerDuration int64 `json:"timeoutWorkerDuration"` // Duration in ms TimeoutSyncThreshold int `json:"timeoutSyncThreshold"` // send syncInfo after number of timeout
CertThreshold int `json:"certificateThreshold"` // Necessary number of messages from master nodes to form a certificate TimeoutPeriod int `json:"timeoutPeriod"` // Duration in ms
SkipV2Validation bool //Skip Block Validation for testing purpose, V2 consensus only CertThreshold int `json:"certificateThreshold"` // Necessary number of messages from master nodes to form a certificate
SkipV2Validation bool //Skip Block Validation for testing purpose, V2 consensus only
} }
// String implements the stringer interface, returning the consensus engine details. // String implements the stringer interface, returning the consensus engine details.