diff --git a/common/countdown/countdown.go b/common/countdown/countdown.go index e914fa8da908..1f753a659ac6 100644 --- a/common/countdown/countdown.go +++ b/common/countdown/countdown.go @@ -23,12 +23,21 @@ type CountdownTimer struct { OnTimeoutFn func(time time.Time, i ...interface{}) error } -func NewCountDown(duration time.Duration) *CountdownTimer { +func NewConstCountDown(duration time.Duration) *CountdownTimer { return &CountdownTimer{ resetc: make(chan int), quitc: make(chan chan struct{}), initilised: false, - durationHelper: NewConstTimeoutDuration(duration), //TODO: change to NewExpTimeoutDuration + durationHelper: NewConstTimeoutDuration(duration), + } +} + +func NewExpCountDown(duration time.Duration, base float64, max_exponent uint8) *CountdownTimer { + return &CountdownTimer{ + resetc: make(chan int), + quitc: make(chan chan struct{}), + initilised: false, + durationHelper: NewExpTimeoutDuration(duration, base, max_exponent), } } diff --git a/common/countdown/countdown_test.go b/common/countdown/countdown_test.go index 382ace22bac0..9112133f026e 100644 --- a/common/countdown/countdown_test.go +++ b/common/countdown/countdown_test.go @@ -16,7 +16,7 @@ func TestCountdownWillCallback(t *testing.T) { return nil } - countdown := NewCountDown(1000 * time.Millisecond) + countdown := NewConstCountDown(1000 * time.Millisecond) countdown.OnTimeoutFn = OnTimeoutFn countdown.Reset(fakeI) <-called @@ -31,7 +31,7 @@ func TestCountdownShouldReset(t *testing.T) { return nil } - countdown := NewCountDown(5000 * time.Millisecond) + countdown := NewConstCountDown(5000 * time.Millisecond) countdown.OnTimeoutFn = OnTimeoutFn // Check countdown did not start assert.False(t, countdown.isInitilised()) @@ -79,7 +79,7 @@ func TestCountdownShouldResetEvenIfErrored(t *testing.T) { return errors.New("ERROR!") } - countdown := NewCountDown(5000 * time.Millisecond) + countdown := NewConstCountDown(5000 * time.Millisecond) countdown.OnTimeoutFn = OnTimeoutFn // Check countdown did not start assert.False(t, countdown.isInitilised()) @@ -127,7 +127,7 @@ func TestCountdownShouldBeAbleToStop(t *testing.T) { return nil } - countdown := NewCountDown(5000 * time.Millisecond) + countdown := NewConstCountDown(5000 * time.Millisecond) countdown.OnTimeoutFn = OnTimeoutFn // Check countdown did not start assert.False(t, countdown.isInitilised()) @@ -144,7 +144,7 @@ func TestCountdownShouldBeAbleToStop(t *testing.T) { func TestCountdownShouldAvoidDeadlock(t *testing.T) { var fakeI interface{} called := make(chan int) - countdown := NewCountDown(5000 * time.Millisecond) + countdown := NewConstCountDown(5000 * time.Millisecond) OnTimeoutFn := func(time.Time, ...interface{}) error { countdown.Reset(fakeI) called <- 1 diff --git a/common/countdown/exp_duration_test.go b/common/countdown/exp_duration_test.go index cfd5a4d283e5..2f2363ea2f95 100644 --- a/common/countdown/exp_duration_test.go +++ b/common/countdown/exp_duration_test.go @@ -50,6 +50,11 @@ func TestExpDuration(t *testing.T) { currentRound++ result = helper.GetTimeoutDuration(nil, currentRound, highestQCRound) assert.Equal(t, duration*time.Duration(base)*time.Duration(base)*time.Duration(base), result) + + // extreme case + helper.SetParams(duration, float64(0), uint8(0)) + result = helper.GetTimeoutDuration(nil, currentRound, highestQCRound) + assert.Equal(t, duration, result) } func TestInvalidParameter(t *testing.T) { diff --git a/consensus/XDPoS/engines/engine_v2/engine.go b/consensus/XDPoS/engines/engine_v2/engine.go index 3462cce54603..5b33756cb8ed 100644 --- a/consensus/XDPoS/engines/engine_v2/engine.go +++ b/consensus/XDPoS/engines/engine_v2/engine.go @@ -75,7 +75,7 @@ func New(chainConfig *params.ChainConfig, db ethdb.Database, minePeriodCh chan i config := chainConfig.XDPoS // Setup timeoutTimer duration := time.Duration(config.V2.CurrentConfig.TimeoutPeriod) * time.Second - timeoutTimer := countdown.NewCountDown(duration) + timeoutTimer := countdown.NewExpCountDown(duration, config.V2.CurrentConfig.ExpTimeoutConfig.Base, config.V2.CurrentConfig.ExpTimeoutConfig.MaxExponent) snapshots, _ := lru.NewARC(utils.InmemorySnapshots) signatures, _ := lru.NewARC(utils.InmemorySnapshots) @@ -143,7 +143,7 @@ func (x *XDPoS_v2) UpdateParams(header *types.Header) { // Setup timeoutTimer duration := time.Duration(x.config.V2.CurrentConfig.TimeoutPeriod) * time.Second - x.timeoutWorker.SetParams(duration) + x.timeoutWorker.SetParams(duration, x.config.V2.CurrentConfig.ExpTimeoutConfig.Base, x.config.V2.CurrentConfig.ExpTimeoutConfig.MaxExponent) // avoid deadlock go func() { diff --git a/params/config.go b/params/config.go index a97f07bfb336..ceacc3b1e87e 100644 --- a/params/config.go +++ b/params/config.go @@ -466,6 +466,13 @@ type V2Config struct { TimeoutSyncThreshold int `json:"timeoutSyncThreshold"` // send syncInfo after number of timeout TimeoutPeriod int `json:"timeoutPeriod"` // Duration in ms CertThreshold float64 `json:"certificateThreshold"` // Necessary number of messages from master nodes to form a certificate + + ExpTimeoutConfig ExpTimeoutConfig `json:"expTimeoutConfig"` +} + +type ExpTimeoutConfig struct { + Base float64 `json:"base"` // base in base^exponent + MaxExponent uint8 `json:"maxExponent"` // max exponent in base^exponent } func (c *XDPoSConfig) String() string {