mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-16 18:00:46 +00:00
Exp timeout (#764)
* feat: write duration calculation in countdown as interface. add more inputs as function argument * feat: ExpTimeoutDuration * fix: three dots usage * feat: refine exp duration * feat: add exp timeout config and use it in countdown * feat: remove const countdown * feat: remove use of interface in countdown, use error * fix: countdown reset timer problem * fix: add default ExpTimeoutConfig for config
This commit is contained in:
parent
38f4c98740
commit
537dc5e6fb
7 changed files with 222 additions and 40 deletions
|
|
@ -5,26 +5,40 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||||
"github.com/XinFinOrg/XDPoSChain/log"
|
"github.com/XinFinOrg/XDPoSChain/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type TimeoutDurationHelper interface {
|
||||||
|
GetTimeoutDuration(types.Round, types.Round) time.Duration
|
||||||
|
SetParams(time.Duration, float64, uint8) error
|
||||||
|
}
|
||||||
|
|
||||||
type CountdownTimer struct {
|
type CountdownTimer struct {
|
||||||
lock sync.RWMutex // Protects the Initilised field
|
lock sync.RWMutex // Protects the Initilised field
|
||||||
resetc chan int
|
resetc chan ResetInfo
|
||||||
quitc chan chan struct{}
|
quitc chan chan struct{}
|
||||||
initilised bool
|
initilised bool
|
||||||
timeoutDuration time.Duration
|
durationHelper TimeoutDurationHelper
|
||||||
// Triggered when the countdown timer timeout for the `timeoutDuration` period, it will pass current timestamp to the callback function
|
// Triggered when the countdown timer timeout for the `timeoutDuration` period, it will pass current timestamp to the callback function
|
||||||
OnTimeoutFn func(time time.Time, i interface{}) error
|
OnTimeoutFn func(time time.Time, i interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCountDown(duration time.Duration) *CountdownTimer {
|
type ResetInfo struct {
|
||||||
return &CountdownTimer{
|
currentRound, highestRound types.Round
|
||||||
resetc: make(chan int),
|
}
|
||||||
quitc: make(chan chan struct{}),
|
|
||||||
initilised: false,
|
func NewExpCountDown(duration time.Duration, base float64, max_exponent uint8) (*CountdownTimer, error) {
|
||||||
timeoutDuration: duration,
|
durationHelper, err := NewExpTimeoutDuration(duration, base, max_exponent)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return &CountdownTimer{
|
||||||
|
resetc: make(chan ResetInfo),
|
||||||
|
quitc: make(chan chan struct{}),
|
||||||
|
initilised: false,
|
||||||
|
durationHelper: durationHelper,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Completely stop the countdown timer from running.
|
// Completely stop the countdown timer from running.
|
||||||
|
|
@ -34,25 +48,25 @@ func (t *CountdownTimer) StopTimer() {
|
||||||
<-q
|
<-q
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *CountdownTimer) SetTimeoutDuration(duration time.Duration) {
|
func (t *CountdownTimer) SetParams(duration time.Duration, base float64, maxExponent uint8) error {
|
||||||
t.timeoutDuration = duration
|
return t.durationHelper.SetParams(duration, base, maxExponent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset will start the countdown timer if it's already stopped, or simply reset the countdown time back to the defual `duration`
|
// Reset will start the countdown timer if it's already stopped, or simply reset the countdown time back to the defual `duration`
|
||||||
func (t *CountdownTimer) Reset(i interface{}) {
|
func (t *CountdownTimer) Reset(i interface{}, currentRound, highestRound types.Round) {
|
||||||
if !t.isInitilised() {
|
if !t.isInitilised() {
|
||||||
t.setInitilised(true)
|
t.setInitilised(true)
|
||||||
go t.startTimer(i)
|
go t.startTimer(i, currentRound, highestRound)
|
||||||
} else {
|
} else {
|
||||||
t.resetc <- 0
|
t.resetc <- ResetInfo{currentRound, highestRound}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A long running process that
|
// A long running process that
|
||||||
func (t *CountdownTimer) startTimer(i interface{}) {
|
func (t *CountdownTimer) startTimer(i interface{}, currentRound, highestRound types.Round) {
|
||||||
// Make sure we mark Initilised to false when we quit the countdown
|
// Make sure we mark Initilised to false when we quit the countdown
|
||||||
defer t.setInitilised(false)
|
defer t.setInitilised(false)
|
||||||
timer := time.NewTimer(t.timeoutDuration)
|
timer := time.NewTimer(t.durationHelper.GetTimeoutDuration(currentRound, highestRound))
|
||||||
// We start with a inf loop
|
// We start with a inf loop
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
|
@ -69,10 +83,15 @@ func (t *CountdownTimer) startTimer(i interface{}) {
|
||||||
}
|
}
|
||||||
log.Debug("OnTimeoutFn processed")
|
log.Debug("OnTimeoutFn processed")
|
||||||
}()
|
}()
|
||||||
timer.Reset(t.timeoutDuration)
|
timer.Reset(t.durationHelper.GetTimeoutDuration(currentRound, highestRound))
|
||||||
case <-t.resetc:
|
case info := <-t.resetc:
|
||||||
log.Debug("Reset countdown timer")
|
log.Debug("Reset countdown timer")
|
||||||
timer.Reset(t.timeoutDuration)
|
currentRound = info.currentRound
|
||||||
|
highestRound = info.highestRound
|
||||||
|
if !timer.Stop() {
|
||||||
|
<-timer.C
|
||||||
|
}
|
||||||
|
timer.Reset(t.durationHelper.GetTimeoutDuration(currentRound, highestRound))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,10 @@ func TestCountdownWillCallback(t *testing.T) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
countdown := NewCountDown(1000 * time.Millisecond)
|
countdown, err := NewExpCountDown(1000*time.Millisecond, 0, 0)
|
||||||
|
assert.Nil(t, err)
|
||||||
countdown.OnTimeoutFn = OnTimeoutFn
|
countdown.OnTimeoutFn = OnTimeoutFn
|
||||||
countdown.Reset(fakeI)
|
countdown.Reset(fakeI, 0, 0)
|
||||||
<-called
|
<-called
|
||||||
t.Log("Times up, successfully called OnTimeoutFn")
|
t.Log("Times up, successfully called OnTimeoutFn")
|
||||||
}
|
}
|
||||||
|
|
@ -31,11 +32,12 @@ func TestCountdownShouldReset(t *testing.T) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
countdown := NewCountDown(5000 * time.Millisecond)
|
countdown, err := NewExpCountDown(5000*time.Millisecond, 0, 0)
|
||||||
|
assert.Nil(t, err)
|
||||||
countdown.OnTimeoutFn = OnTimeoutFn
|
countdown.OnTimeoutFn = OnTimeoutFn
|
||||||
// Check countdown did not start
|
// Check countdown did not start
|
||||||
assert.False(t, countdown.isInitilised())
|
assert.False(t, countdown.isInitilised())
|
||||||
countdown.Reset(fakeI)
|
countdown.Reset(fakeI, 0, 0)
|
||||||
// Now the countdown should already started
|
// Now the countdown should already started
|
||||||
assert.True(t, countdown.isInitilised())
|
assert.True(t, countdown.isInitilised())
|
||||||
expectedCalledTime := time.Now().Add(9000 * time.Millisecond)
|
expectedCalledTime := time.Now().Add(9000 * time.Millisecond)
|
||||||
|
|
@ -54,7 +56,7 @@ firstReset:
|
||||||
}
|
}
|
||||||
break firstReset
|
break firstReset
|
||||||
case <-resetTimer.C:
|
case <-resetTimer.C:
|
||||||
countdown.Reset(fakeI)
|
countdown.Reset(fakeI, 0, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,11 +81,12 @@ func TestCountdownShouldResetEvenIfErrored(t *testing.T) {
|
||||||
return errors.New("ERROR!")
|
return errors.New("ERROR!")
|
||||||
}
|
}
|
||||||
|
|
||||||
countdown := NewCountDown(5000 * time.Millisecond)
|
countdown, err := NewExpCountDown(5000*time.Millisecond, 0, 0)
|
||||||
|
assert.Nil(t, err)
|
||||||
countdown.OnTimeoutFn = OnTimeoutFn
|
countdown.OnTimeoutFn = OnTimeoutFn
|
||||||
// Check countdown did not start
|
// Check countdown did not start
|
||||||
assert.False(t, countdown.isInitilised())
|
assert.False(t, countdown.isInitilised())
|
||||||
countdown.Reset(fakeI)
|
countdown.Reset(fakeI, 0, 0)
|
||||||
// Now the countdown should already started
|
// Now the countdown should already started
|
||||||
assert.True(t, countdown.isInitilised())
|
assert.True(t, countdown.isInitilised())
|
||||||
expectedCalledTime := time.Now().Add(9000 * time.Millisecond)
|
expectedCalledTime := time.Now().Add(9000 * time.Millisecond)
|
||||||
|
|
@ -102,7 +105,7 @@ firstReset:
|
||||||
}
|
}
|
||||||
break firstReset
|
break firstReset
|
||||||
case <-resetTimer.C:
|
case <-resetTimer.C:
|
||||||
countdown.Reset(fakeI)
|
countdown.Reset(fakeI, 0, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,11 +130,12 @@ func TestCountdownShouldBeAbleToStop(t *testing.T) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
countdown := NewCountDown(5000 * time.Millisecond)
|
countdown, err := NewExpCountDown(5000*time.Millisecond, 0, 0)
|
||||||
|
assert.Nil(t, err)
|
||||||
countdown.OnTimeoutFn = OnTimeoutFn
|
countdown.OnTimeoutFn = OnTimeoutFn
|
||||||
// Check countdown did not start
|
// Check countdown did not start
|
||||||
assert.False(t, countdown.isInitilised())
|
assert.False(t, countdown.isInitilised())
|
||||||
countdown.Reset(fakeI)
|
countdown.Reset(fakeI, 0, 0)
|
||||||
// Now the countdown should already started
|
// Now the countdown should already started
|
||||||
assert.True(t, countdown.isInitilised())
|
assert.True(t, countdown.isInitilised())
|
||||||
// Try manually stop the timer before it triggers the callback
|
// Try manually stop the timer before it triggers the callback
|
||||||
|
|
@ -144,14 +148,15 @@ func TestCountdownShouldBeAbleToStop(t *testing.T) {
|
||||||
func TestCountdownShouldAvoidDeadlock(t *testing.T) {
|
func TestCountdownShouldAvoidDeadlock(t *testing.T) {
|
||||||
var fakeI interface{}
|
var fakeI interface{}
|
||||||
called := make(chan int)
|
called := make(chan int)
|
||||||
countdown := NewCountDown(5000 * time.Millisecond)
|
countdown, err := NewExpCountDown(5000*time.Millisecond, 0, 0)
|
||||||
|
assert.Nil(t, err)
|
||||||
OnTimeoutFn := func(time.Time, interface{}) error {
|
OnTimeoutFn := func(time.Time, interface{}) error {
|
||||||
countdown.Reset(fakeI)
|
countdown.Reset(fakeI, 0, 0)
|
||||||
called <- 1
|
called <- 1
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
countdown.OnTimeoutFn = OnTimeoutFn
|
countdown.OnTimeoutFn = OnTimeoutFn
|
||||||
countdown.Reset(fakeI)
|
countdown.Reset(fakeI, 0, 0)
|
||||||
<-called
|
<-called
|
||||||
}
|
}
|
||||||
|
|
|
||||||
70
common/countdown/exp_duration.go
Normal file
70
common/countdown/exp_duration.go
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
// A countdown timer that will mostly be used by XDPoS v2 consensus engine
|
||||||
|
package countdown
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxExponentUpperbound uint8 = 32
|
||||||
|
|
||||||
|
type ExpTimeoutDuration struct {
|
||||||
|
duration time.Duration
|
||||||
|
base float64
|
||||||
|
maxExponent uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewExpTimeoutDuration(duration time.Duration, base float64, maxExponent uint8) (*ExpTimeoutDuration, error) {
|
||||||
|
d := &ExpTimeoutDuration{
|
||||||
|
duration: duration,
|
||||||
|
base: base,
|
||||||
|
maxExponent: maxExponent,
|
||||||
|
}
|
||||||
|
err := d.sanityCheck()
|
||||||
|
return d, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ExpTimeoutDuration) sanityCheck() error {
|
||||||
|
if d.maxExponent >= maxExponentUpperbound {
|
||||||
|
return fmt.Errorf("max_exponent (%d)= >= max_exponent_upperbound (%d)", d.maxExponent, maxExponentUpperbound)
|
||||||
|
}
|
||||||
|
if math.Pow(d.base, float64(d.maxExponent)) >= float64(math.MaxUint32) {
|
||||||
|
return fmt.Errorf("base^max_exponent (%f^%d) should be less than 2^32", d.base, d.maxExponent)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// The inputs should be: currentRound, highestQuorumCert's round
|
||||||
|
func (d *ExpTimeoutDuration) GetTimeoutDuration(currentRound, highestRound types.Round) time.Duration {
|
||||||
|
power := float64(1)
|
||||||
|
// below statement must be true, just to prevent negative result
|
||||||
|
if highestRound < currentRound {
|
||||||
|
exp := uint8(currentRound-highestRound) - 1
|
||||||
|
if exp > d.maxExponent {
|
||||||
|
exp = d.maxExponent
|
||||||
|
}
|
||||||
|
power = math.Pow(d.base, float64(exp))
|
||||||
|
}
|
||||||
|
return d.duration * time.Duration(power)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ExpTimeoutDuration) SetParams(duration time.Duration, base float64, maxExponent uint8) error {
|
||||||
|
prevDuration := d.duration
|
||||||
|
prevBase := d.base
|
||||||
|
prevME := d.maxExponent
|
||||||
|
|
||||||
|
d.duration = duration
|
||||||
|
d.base = base
|
||||||
|
d.maxExponent = maxExponent
|
||||||
|
// if parameters are wrong, should remain instead of change or panic
|
||||||
|
if err := d.sanityCheck(); err != nil {
|
||||||
|
d.duration = prevDuration
|
||||||
|
d.base = prevBase
|
||||||
|
d.maxExponent = prevME
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
65
common/countdown/exp_duration_test.go
Normal file
65
common/countdown/exp_duration_test.go
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
package countdown
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExpDuration(t *testing.T) {
|
||||||
|
base := float64(2.0)
|
||||||
|
max_exponent := uint8(2)
|
||||||
|
duration := time.Second * 59
|
||||||
|
helper, err := NewExpTimeoutDuration(duration, base, max_exponent)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
// round 10 = 9+1, normal case, should be base
|
||||||
|
currentRound := types.Round(10)
|
||||||
|
highestQCRound := types.Round(9)
|
||||||
|
result := helper.GetTimeoutDuration(currentRound, highestQCRound)
|
||||||
|
assert.Equal(t, duration, result)
|
||||||
|
|
||||||
|
// round 11 = 9+2, already 1 round timeout, should be base*exponent
|
||||||
|
currentRound++
|
||||||
|
result = helper.GetTimeoutDuration(currentRound, highestQCRound)
|
||||||
|
assert.Equal(t, duration*time.Duration(base), result)
|
||||||
|
|
||||||
|
// round 12 = 9+3, already 2 rounds timeout, should be base*exponent^2
|
||||||
|
currentRound++
|
||||||
|
result = helper.GetTimeoutDuration(currentRound, highestQCRound)
|
||||||
|
assert.Equal(t, duration*time.Duration(base)*time.Duration(base), result)
|
||||||
|
|
||||||
|
// test SetParams
|
||||||
|
duration++
|
||||||
|
max_exponent++
|
||||||
|
base++
|
||||||
|
helper.SetParams(duration, base, max_exponent)
|
||||||
|
result = helper.GetTimeoutDuration(currentRound, highestQCRound)
|
||||||
|
assert.Equal(t, duration*time.Duration(base)*time.Duration(base), result)
|
||||||
|
// round 14 = 9+5, already 4 rounds timeout, but max_exponent=3, should be base*exponent^3
|
||||||
|
currentRound++
|
||||||
|
currentRound++
|
||||||
|
result = helper.GetTimeoutDuration(currentRound, highestQCRound)
|
||||||
|
assert.Equal(t, duration*time.Duration(math.Pow(base, float64(3))), result)
|
||||||
|
|
||||||
|
// extreme case
|
||||||
|
helper.SetParams(duration, float64(0), uint8(0))
|
||||||
|
result = helper.GetTimeoutDuration(currentRound, highestQCRound)
|
||||||
|
assert.Equal(t, duration, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidParameter(t *testing.T) {
|
||||||
|
base := float64(2.0)
|
||||||
|
max_exponent := uint8(32)
|
||||||
|
duration := time.Second * 59
|
||||||
|
_, err := NewExpTimeoutDuration(duration, base, max_exponent)
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
base = float64(3.0)
|
||||||
|
max_exponent = uint8(21)
|
||||||
|
duration = time.Second * 59
|
||||||
|
_, err = NewExpTimeoutDuration(duration, base, max_exponent)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
@ -76,7 +76,10 @@ func New(chainConfig *params.ChainConfig, db ethdb.Database, minePeriodCh chan i
|
||||||
config := chainConfig.XDPoS
|
config := chainConfig.XDPoS
|
||||||
// Setup timeoutTimer
|
// Setup timeoutTimer
|
||||||
duration := time.Duration(config.V2.CurrentConfig.TimeoutPeriod) * time.Second
|
duration := time.Duration(config.V2.CurrentConfig.TimeoutPeriod) * time.Second
|
||||||
timeoutTimer := countdown.NewCountDown(duration)
|
timeoutTimer, err := countdown.NewExpCountDown(duration, config.V2.CurrentConfig.ExpTimeoutConfig.Base, config.V2.CurrentConfig.ExpTimeoutConfig.MaxExponent)
|
||||||
|
if err != nil {
|
||||||
|
log.Crit("create exp countdown", "err", err)
|
||||||
|
}
|
||||||
|
|
||||||
timeoutPool := utils.NewPool()
|
timeoutPool := utils.NewPool()
|
||||||
votePool := utils.NewPool()
|
votePool := utils.NewPool()
|
||||||
|
|
@ -139,8 +142,10 @@ func (x *XDPoS_v2) UpdateParams(header *types.Header) {
|
||||||
|
|
||||||
// Setup timeoutTimer
|
// Setup timeoutTimer
|
||||||
duration := time.Duration(x.config.V2.CurrentConfig.TimeoutPeriod) * time.Second
|
duration := time.Duration(x.config.V2.CurrentConfig.TimeoutPeriod) * time.Second
|
||||||
x.timeoutWorker.SetTimeoutDuration(duration)
|
err = x.timeoutWorker.SetParams(duration, x.config.V2.CurrentConfig.ExpTimeoutConfig.Base, x.config.V2.CurrentConfig.ExpTimeoutConfig.MaxExponent)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[UpdateParams] set params failed", "err", err)
|
||||||
|
}
|
||||||
// avoid deadlock
|
// avoid deadlock
|
||||||
go func() {
|
go func() {
|
||||||
x.minePeriodCh <- x.config.V2.CurrentConfig.MinePeriod
|
x.minePeriodCh <- x.config.V2.CurrentConfig.MinePeriod
|
||||||
|
|
@ -253,7 +258,7 @@ func (x *XDPoS_v2) initial(chain consensus.ChainReader, header *types.Header) er
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Kick-off the countdown timer
|
// Kick-off the countdown timer
|
||||||
x.timeoutWorker.Reset(chain)
|
x.timeoutWorker.Reset(chain, 0, 0)
|
||||||
x.isInitilised = true
|
x.isInitilised = true
|
||||||
|
|
||||||
log.Warn("[initial] finish initialisation")
|
log.Warn("[initial] finish initialisation")
|
||||||
|
|
@ -915,7 +920,7 @@ func (x *XDPoS_v2) setNewRound(blockChainReader consensus.ChainReader, round typ
|
||||||
log.Info("[setNewRound] new round and reset pools and workers", "round", round)
|
log.Info("[setNewRound] new round and reset pools and workers", "round", round)
|
||||||
x.currentRound = round
|
x.currentRound = round
|
||||||
x.timeoutCount = 0
|
x.timeoutCount = 0
|
||||||
x.timeoutWorker.Reset(blockChainReader)
|
x.timeoutWorker.Reset(blockChainReader, x.currentRound, x.highestQuorumCert.ProposedBlockInfo.Round)
|
||||||
x.timeoutPool.Clear()
|
x.timeoutPool.Clear()
|
||||||
// don't need to clean vote pool, we have other process to clean and it's not good to clean here, some edge case may break
|
// don't need to clean vote pool, we have other process to clean and it's not good to clean here, some edge case may break
|
||||||
// for example round gets bump during collecting vote, so we have to keep vote.
|
// for example round gets bump during collecting vote, so we have to keep vote.
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ func (x *XDPoS_v2) SetNewRoundFaker(blockChainReader consensus.ChainReader, newR
|
||||||
defer x.lock.Unlock()
|
defer x.lock.Unlock()
|
||||||
// Reset a bunch of things
|
// Reset a bunch of things
|
||||||
if resetTimer {
|
if resetTimer {
|
||||||
x.timeoutWorker.Reset(blockChainReader)
|
x.timeoutWorker.Reset(blockChainReader, 0, 0)
|
||||||
}
|
}
|
||||||
x.currentRound = newRound
|
x.currentRound = newRound
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ var (
|
||||||
TimeoutSyncThreshold: 3,
|
TimeoutSyncThreshold: 3,
|
||||||
TimeoutPeriod: 30,
|
TimeoutPeriod: 30,
|
||||||
MinePeriod: 2,
|
MinePeriod: 2,
|
||||||
|
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
|
||||||
},
|
},
|
||||||
2000: {
|
2000: {
|
||||||
MaxMasternodes: 108,
|
MaxMasternodes: 108,
|
||||||
|
|
@ -55,6 +56,7 @@ var (
|
||||||
TimeoutSyncThreshold: 2,
|
TimeoutSyncThreshold: 2,
|
||||||
TimeoutPeriod: 600,
|
TimeoutPeriod: 600,
|
||||||
MinePeriod: 2,
|
MinePeriod: 2,
|
||||||
|
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
|
||||||
},
|
},
|
||||||
8000: {
|
8000: {
|
||||||
MaxMasternodes: 108,
|
MaxMasternodes: 108,
|
||||||
|
|
@ -63,6 +65,7 @@ var (
|
||||||
TimeoutSyncThreshold: 2,
|
TimeoutSyncThreshold: 2,
|
||||||
TimeoutPeriod: 60,
|
TimeoutPeriod: 60,
|
||||||
MinePeriod: 2,
|
MinePeriod: 2,
|
||||||
|
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
|
||||||
},
|
},
|
||||||
220000: {
|
220000: {
|
||||||
MaxMasternodes: 108,
|
MaxMasternodes: 108,
|
||||||
|
|
@ -71,6 +74,7 @@ var (
|
||||||
TimeoutSyncThreshold: 2,
|
TimeoutSyncThreshold: 2,
|
||||||
TimeoutPeriod: 30,
|
TimeoutPeriod: 30,
|
||||||
MinePeriod: 2,
|
MinePeriod: 2,
|
||||||
|
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
|
||||||
},
|
},
|
||||||
460000: {
|
460000: {
|
||||||
MaxMasternodes: 108,
|
MaxMasternodes: 108,
|
||||||
|
|
@ -79,6 +83,7 @@ var (
|
||||||
TimeoutSyncThreshold: 2,
|
TimeoutSyncThreshold: 2,
|
||||||
TimeoutPeriod: 20,
|
TimeoutPeriod: 20,
|
||||||
MinePeriod: 2,
|
MinePeriod: 2,
|
||||||
|
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,6 +95,7 @@ var (
|
||||||
TimeoutSyncThreshold: 3,
|
TimeoutSyncThreshold: 3,
|
||||||
TimeoutPeriod: 60,
|
TimeoutPeriod: 60,
|
||||||
MinePeriod: 2,
|
MinePeriod: 2,
|
||||||
|
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
|
||||||
},
|
},
|
||||||
900000: {
|
900000: {
|
||||||
MaxMasternodes: 108,
|
MaxMasternodes: 108,
|
||||||
|
|
@ -98,6 +104,7 @@ var (
|
||||||
TimeoutSyncThreshold: 3,
|
TimeoutSyncThreshold: 3,
|
||||||
TimeoutPeriod: 60,
|
TimeoutPeriod: 60,
|
||||||
MinePeriod: 2,
|
MinePeriod: 2,
|
||||||
|
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,6 +116,7 @@ var (
|
||||||
TimeoutSyncThreshold: 3,
|
TimeoutSyncThreshold: 3,
|
||||||
TimeoutPeriod: 30,
|
TimeoutPeriod: 30,
|
||||||
MinePeriod: 2,
|
MinePeriod: 2,
|
||||||
|
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,6 +128,7 @@ var (
|
||||||
TimeoutSyncThreshold: 2,
|
TimeoutSyncThreshold: 2,
|
||||||
TimeoutPeriod: 4,
|
TimeoutPeriod: 4,
|
||||||
MinePeriod: 2,
|
MinePeriod: 2,
|
||||||
|
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
|
||||||
},
|
},
|
||||||
10: {
|
10: {
|
||||||
MaxMasternodes: 18,
|
MaxMasternodes: 18,
|
||||||
|
|
@ -128,6 +137,7 @@ var (
|
||||||
TimeoutSyncThreshold: 2,
|
TimeoutSyncThreshold: 2,
|
||||||
TimeoutPeriod: 4,
|
TimeoutPeriod: 4,
|
||||||
MinePeriod: 3,
|
MinePeriod: 3,
|
||||||
|
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
|
||||||
},
|
},
|
||||||
900: {
|
900: {
|
||||||
MaxMasternodes: 20,
|
MaxMasternodes: 20,
|
||||||
|
|
@ -136,6 +146,7 @@ var (
|
||||||
TimeoutSyncThreshold: 4,
|
TimeoutSyncThreshold: 4,
|
||||||
TimeoutPeriod: 5,
|
TimeoutPeriod: 5,
|
||||||
MinePeriod: 2,
|
MinePeriod: 2,
|
||||||
|
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -448,6 +459,13 @@ type V2Config struct {
|
||||||
TimeoutSyncThreshold int `json:"timeoutSyncThreshold"` // send syncInfo after number of timeout
|
TimeoutSyncThreshold int `json:"timeoutSyncThreshold"` // send syncInfo after number of timeout
|
||||||
TimeoutPeriod int `json:"timeoutPeriod"` // Duration in ms
|
TimeoutPeriod int `json:"timeoutPeriod"` // Duration in ms
|
||||||
CertThreshold float64 `json:"certificateThreshold"` // Necessary number of messages from master nodes to form a certificate
|
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 {
|
func (c *XDPoSConfig) String() string {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue