From be9dfa5853de800a763dd6fde5a5915f98a2ed80 Mon Sep 17 00:00:00 2001 From: jiangzehua <1092431698@qq.com> Date: Wed, 28 Jun 2023 16:23:44 +0800 Subject: [PATCH] feat(bpos): adjust change view logic and revert to pow logic --- cmd/script/api/dposmanager.go | 5 +- common/config/config.go | 20 +++++++ core/transaction/reverttopowtransaction.go | 8 ++- dpos/arbitrator.go | 12 +++- dpos/manager/consensus.go | 29 +++++++--- dpos/manager/proposaldispatcher.go | 8 +-- dpos/manager/view.go | 67 +++++++++++++++++----- pow/revertlistener.go | 14 ++++- 8 files changed, 128 insertions(+), 35 deletions(-) diff --git a/cmd/script/api/dposmanager.go b/cmd/script/api/dposmanager.go index a23ea405e..1e378aa74 100644 --- a/cmd/script/api/dposmanager.go +++ b/cmd/script/api/dposmanager.go @@ -8,6 +8,7 @@ package api import ( "encoding/json" "fmt" + "math" "strconv" "time" @@ -88,7 +89,7 @@ func newDposManager(L *lua.LState) int { TimeSource: medianTime, }) - mockManager.Consensus = NewConsensus(dposManager, 5*time.Second, mockManager.Handler) + mockManager.Consensus = NewConsensus(dposManager, 5*time.Second, mockManager.Handler, math.MaxUint32) mockManager.Dispatcher, mockManager.IllegalMonitor = NewDispatcherAndIllegalMonitor(ProposalDispatcherConfig{ EventMonitor: mockManager.EventMonitor, Consensus: mockManager.Consensus, @@ -324,7 +325,7 @@ func dposManagerSignVote(L *lua.LState) int { return 1 } -//mock object of dpos manager +// mock object of dpos manager type manager struct { *DPOSManager Account account.Account diff --git a/common/config/config.go b/common/config/config.go index 7b4b0873c..f4b58ee81 100644 --- a/common/config/config.go +++ b/common/config/config.go @@ -180,6 +180,10 @@ func GetDefaultParams() *Configuration { MaxInactiveRoundsOfRandomNode: 36 * 8, RevertToPOWNoBlockTime: 12 * 3600, StopConfirmBlockTime: 11 * 3600, + RevertToPOWV1Height: math.MaxUint32, // todo complete me + RevertToPOWNoBlockTimeV1: 2 * 3600, // todo complete me + StopConfirmBlockTimeV1: 6600, // todo complete me + ChangeViewV1Height: math.MaxUint32, // todo complete me DPoSV2IllegalPenalty: 20000000000, DPOSNodeCrossChainHeight: math.MaxUint32, DPoSV2DepositCoinMinLockTime: 7200, @@ -360,6 +364,10 @@ func (p *Configuration) TestNet() *Configuration { p.MaxReservedCustomIDLength = 255 p.DPoSConfiguration.RevertToPOWNoBlockTime = 12 * 3600 p.DPoSConfiguration.StopConfirmBlockTime = 11 * 3600 + p.DPoSConfiguration.RevertToPOWV1Height = math.MaxUint32 // todo complete me + p.DPoSConfiguration.RevertToPOWNoBlockTimeV1 = 2 * 3600 // todo complete me + p.DPoSConfiguration.StopConfirmBlockTimeV1 = 6600 // todo complete me + p.DPoSConfiguration.ChangeViewV1Height = math.MaxUint32 // todo complete me p.DPoSConfiguration.RevertToPOWStartHeight = 815060 p.HalvingRewardHeight = 877880 //767000 + 154 * 720 p.HalvingRewardInterval = 1051200 //4 * 365 * 720 @@ -484,6 +492,10 @@ func (p *Configuration) RegNet() *Configuration { p.MaxReservedCustomIDLength = 255 p.DPoSConfiguration.RevertToPOWNoBlockTime = 12 * 3600 p.DPoSConfiguration.StopConfirmBlockTime = 11 * 3600 + p.DPoSConfiguration.RevertToPOWV1Height = math.MaxUint32 // todo complete me + p.DPoSConfiguration.RevertToPOWNoBlockTimeV1 = 2 * 3600 // todo complete me + p.DPoSConfiguration.StopConfirmBlockTimeV1 = 6600 // todo complete me + p.DPoSConfiguration.ChangeViewV1Height = math.MaxUint32 // todo complete me p.DPoSConfiguration.RevertToPOWStartHeight = 706240 p.HalvingRewardHeight = 801240 //690360 + 154 * 720 p.HalvingRewardInterval = 1051200 //4 * 365 * 720 @@ -721,6 +733,14 @@ type DPoSConfiguration struct { RevertToPOWNoBlockTime int64 `screw:"--reverttopownoblocktime" usage:"defines how long time does it take to revert to POW mode"` // StopConfirmBlockTime defines how long time dose it take before stop confirm block. StopConfirmBlockTime int64 `screw:"--stopconfirmblocktime" usage:"defines how long time does it take to stop confirm block"` + // RevertToPOWV1Height defines how the height of POW mode of version 1.0 + RevertToPOWV1Height uint32 `screw:"--reverttopowv1height" usage:"defines how the height of POW mode of version 1.0"` + // RevertToPOWInterval defines how long time does it take to revert to POW mode. + RevertToPOWNoBlockTimeV1 int64 `screw:"--reverttopownoblocktimev1" usage:"defines how long time does it take to revert to POW mode"` + // StopConfirmBlockTime defines how long time dose it take before stop confirm block. + StopConfirmBlockTimeV1 int64 `screw:"--stopconfirmblocktimev1" usage:"defines how long time does it take to stop confirm block"` + // ChangeViewV1Height defines the height of ChangeView version 1.0 + ChangeViewV1Height uint32 `screw:"--changeviewv1height" usage:"defines how the height of ChangeView version 1.0"` // RevertToPOWStartHeight defines the start height to allow to revert to POW mode. RevertToPOWStartHeight uint32 `screw:"--reverttopowstartheight" usage:"defines the start height to allow to revert to POW mode"` // DPoSV2RewardAccumulateAddress defines the dposv2 reward accumulating address diff --git a/core/transaction/reverttopowtransaction.go b/core/transaction/reverttopowtransaction.go index 69eec9289..ba6f1ed23 100644 --- a/core/transaction/reverttopowtransaction.go +++ b/core/transaction/reverttopowtransaction.go @@ -80,7 +80,13 @@ func (t *RevertToPOWTransaction) SpecialContextCheck() (result elaerr.ELAError, switch p.Type { case payload.NoBlock: lastBlockTime := int64(t.parameters.BlockChain.BestChain.Timestamp) - noBlockTime := t.parameters.Config.DPoSConfiguration.RevertToPOWNoBlockTime + + var noBlockTime int64 + if t.parameters.BlockHeight < t.parameters.Config.DPoSConfiguration.RevertToPOWV1Height { + noBlockTime = t.parameters.Config.DPoSConfiguration.RevertToPOWNoBlockTime + } else { + noBlockTime = t.parameters.Config.DPoSConfiguration.RevertToPOWNoBlockTimeV1 + } if t.parameters.TimeStamp == 0 { // is not in block, check by local time. diff --git a/dpos/arbitrator.go b/dpos/arbitrator.go index 0ea75a272..edae3230a 100644 --- a/dpos/arbitrator.go +++ b/dpos/arbitrator.go @@ -204,7 +204,15 @@ func (a *Arbitrator) OnBlockReceived(b *types.Block, confirmed bool) { if b.Height >= a.cfg.ChainParams.DPoSConfiguration.RevertToPOWStartHeight { lastBlockTimestamp := int64(a.cfg.Arbitrators.GetLastBlockTimestamp()) localTimestamp := a.cfg.Chain.TimeSource.AdjustedTime().Unix() - if localTimestamp-lastBlockTimestamp >= a.cfg.ChainParams.DPoSConfiguration.StopConfirmBlockTime { + + var stopConfirmTime int64 + if b.Height < a.cfg.ChainParams.DPoSConfiguration.RevertToPOWV1Height { + stopConfirmTime = a.cfg.ChainParams.DPoSConfiguration.StopConfirmBlockTime + } else { + stopConfirmTime = a.cfg.ChainParams.DPoSConfiguration.StopConfirmBlockTime + } + + if localTimestamp-lastBlockTimestamp >= stopConfirmTime { return } } @@ -281,7 +289,7 @@ func NewArbitrator(account account.Account, cfg Config) (*Arbitrator, error) { consensus := manager.NewConsensus(dposManager, cfg.ChainParams.DPoSConfiguration.SignTolerance, - dposHandlerSwitch) + dposHandlerSwitch, cfg.ChainParams.DPoSConfiguration.ChangeViewV1Height) proposalDispatcher, illegalMonitor := manager.NewDispatcherAndIllegalMonitor( manager.ProposalDispatcherConfig{ EventMonitor: eventMonitor, diff --git a/dpos/manager/consensus.go b/dpos/manager/consensus.go index ce6d2dd4b..b2e9143da 100644 --- a/dpos/manager/consensus.go +++ b/dpos/manager/consensus.go @@ -23,6 +23,7 @@ const ( ) type Consensus struct { + finishedHeight uint32 consensusStatus uint32 viewOffset uint32 @@ -31,16 +32,17 @@ type Consensus struct { } func NewConsensus(manager *DPOSManager, tolerance time.Duration, - viewListener ViewListener) *Consensus { + viewListener ViewListener, changeViewV1Height uint32) *Consensus { c := &Consensus{ consensusStatus: consensusReady, viewOffset: DefaultViewOffset, manager: manager, currentView: view{ - publicKey: manager.publicKey, - signTolerance: tolerance, - listener: viewListener, - arbitrators: manager.arbitrators, + publicKey: manager.publicKey, + signTolerance: tolerance, + listener: viewListener, + arbitrators: manager.arbitrators, + changeViewV1Height: changeViewV1Height, }, } @@ -60,7 +62,8 @@ func (c *Consensus) SetRunning() { c.resetViewOffset() } -func (c *Consensus) SetReady() { +func (c *Consensus) SetReady(height uint32) { + c.finishedHeight = height c.consensusStatus = consensusReady c.resetViewOffset() } @@ -110,12 +113,22 @@ func (c *Consensus) ProcessBlock(b *types.Block) { } func (c *Consensus) ChangeView() { - c.currentView.ChangeView(&c.viewOffset, c.manager.timeSource.AdjustedTime()) + if c.finishedHeight < c.manager.chainParams.DPoSConfiguration.ChangeViewV1Height { + c.currentView.ChangeView(&c.viewOffset, c.manager.timeSource.AdjustedTime()) + } else { + c.currentView.ChangeViewV1(&c.viewOffset, c.manager.timeSource.AdjustedTime()) + } + } func (c *Consensus) TryChangeView() bool { if c.IsRunning() { - return c.currentView.TryChangeView(&c.viewOffset, c.manager.timeSource.AdjustedTime()) + if c.finishedHeight < c.manager.chainParams.DPoSConfiguration.ChangeViewV1Height { + return c.currentView.TryChangeView(&c.viewOffset, c.manager.timeSource.AdjustedTime()) + } else { + return c.currentView.TryChangeViewV1(&c.viewOffset, c.manager.timeSource.AdjustedTime()) + } + } return false } diff --git a/dpos/manager/proposaldispatcher.go b/dpos/manager/proposaldispatcher.go index 77e4ed50a..6c118de21 100644 --- a/dpos/manager/proposaldispatcher.go +++ b/dpos/manager/proposaldispatcher.go @@ -399,19 +399,19 @@ func (p *ProposalDispatcher) FinishConsensus(height uint32, blockHash common.Uin p.cfg.Manager.changeOnDuty() c := log.ConsensusEvent{EndTime: p.cfg.TimeSource.AdjustedTime(), Height: height} p.cfg.EventMonitor.OnConsensusFinished(&c) - p.cfg.Consensus.SetReady() + p.cfg.Consensus.SetReady(height) p.CleanProposals(false) p.resetViewRequests = make(map[string]struct{}, 0) } } -func (p *ProposalDispatcher) resetConsensus() { +func (p *ProposalDispatcher) resetConsensus(height uint32) { log.Info("[resetConsensus] start") defer log.Info("[resetConsensus] end") if p.cfg.Consensus.IsRunning() { log.Info("[resetConsensus] reset view") - p.cfg.Consensus.SetReady() + p.cfg.Consensus.SetReady(height) p.CleanProposals(false) } } @@ -678,7 +678,7 @@ func (p *ProposalDispatcher) OnResponseResetViewReceived(msg *dmsg.ResetView) { if len(p.resetViewRequests) >= p.cfg.Arbitrators.GetArbitersMajorityCount() { log.Info("[OnResponseResetViewReceived] signer:", common.BytesToHexString(signer)) // do reset - p.resetConsensus() + p.resetConsensus(p.finishedHeight) p.resetViewRequests = make(map[string]struct{}, 0) } } diff --git a/dpos/manager/view.go b/dpos/manager/view.go index cbc92f846..cfeb15bf8 100644 --- a/dpos/manager/view.go +++ b/dpos/manager/view.go @@ -15,16 +15,22 @@ import ( "github.com/elastos/Elastos.ELA/dpos/state" ) +const ( + ChangeViewAddStep = uint32(3) + ChangeViewMulStep = uint32(20) +) + type ViewListener interface { OnViewChanged(isOnDuty bool) } type view struct { - publicKey []byte - signTolerance time.Duration - viewStartTime time.Time - isDposOnDuty bool - arbitrators state.Arbitrators + publicKey []byte + signTolerance time.Duration + viewStartTime time.Time + isDposOnDuty bool + changeViewV1Height uint32 + arbitrators state.Arbitrators listener ViewListener } @@ -46,16 +52,27 @@ func (v *view) ResetView(t time.Time) { } func (v *view) ChangeView(viewOffset *uint32, now time.Time) { - //offset, offsetTime := v.calculateOffsetTimeV0(v.viewStartTime, now) - //*viewOffset += uint32(offset) + offset, offsetTime := v.calculateOffsetTimeV0(v.viewStartTime, now) + *viewOffset += offset + + v.viewStartTime = now.Add(-offsetTime) + + if offset > 0 { + currentArbiter := v.arbitrators.GetNextOnDutyArbitrator(*viewOffset) + v.isDposOnDuty = bytes.Equal(currentArbiter, v.publicKey) + log.Info("current onduty arbiter:", + common.BytesToHexString(currentArbiter)) + + v.listener.OnViewChanged(v.isDposOnDuty) + } +} + +func (v *view) ChangeViewV1(viewOffset *uint32, now time.Time) { arbitersCount := v.arbitrators.GetArbitersCount() offset, offsetTime := v.calculateOffsetTimeV1(*viewOffset, v.viewStartTime, now, uint32(arbitersCount)) - *viewOffset = uint32(offset) - - //offset, offsetTime := v.calculateOffsetTimeV2(*viewOffset, v.viewStartTime, now, uint32(arbitersCount)) - //*viewOffset = uint32(offset) + *viewOffset = offset v.viewStartTime = now.Add(-offsetTime) @@ -81,15 +98,26 @@ func (v *view) calculateOffsetTimeV0(startTime time.Time, func (v *view) calculateOffsetTimeV1(currentViewOffset uint32, startTime time.Time, now time.Time, arbitersCount uint32) (uint32, time.Duration) { - step := float64(3) - duration := now.Sub(startTime) + currentOffset := currentViewOffset + duration := now.Sub(startTime) - offsetSeconds := time.Duration(5*math.Pow(step, float64(currentOffset/arbitersCount))) * time.Second + var offsetSeconds time.Duration + if currentOffset < arbitersCount { + offsetSeconds = 5 * time.Second + } else { + offsetSeconds = time.Duration(5+(currentOffset-arbitersCount)*ChangeViewAddStep* + uint32(math.Pow(float64(ChangeViewMulStep), float64(currentOffset/arbitersCount)))) * time.Second + } for duration >= offsetSeconds { currentOffset++ duration -= offsetSeconds - offsetSeconds = time.Duration(5*math.Pow(step, float64(currentOffset/arbitersCount))) * time.Second + if currentOffset < arbitersCount { + offsetSeconds = 5 * time.Second + } else { + offsetSeconds = time.Duration(5+(currentOffset-arbitersCount)*ChangeViewAddStep* + uint32(math.Pow(float64(ChangeViewMulStep), float64(currentOffset/arbitersCount)))) * time.Second + } } return currentOffset, duration @@ -119,6 +147,15 @@ func (v *view) TryChangeView(viewOffset *uint32, now time.Time) bool { return false } +func (v *view) TryChangeViewV1(viewOffset *uint32, now time.Time) bool { + if now.After(v.viewStartTime.Add(v.signTolerance)) { + log.Info("[TryChangeView] succeed") + v.ChangeViewV1(viewOffset, now) + return true + } + return false +} + func (v *view) GetViewInterval() time.Duration { return v.signTolerance } diff --git a/pow/revertlistener.go b/pow/revertlistener.go index 778ce99bd..87e8e4c9f 100644 --- a/pow/revertlistener.go +++ b/pow/revertlistener.go @@ -21,7 +21,8 @@ func (pow *Service) ListenForRevert() { go func() { for { time.Sleep(CheckRevertToPOWInterval) - if pow.chain.BestChain.Height < pow.chainParams.DPoSConfiguration.RevertToPOWStartHeight { + currentHeight := pow.chain.BestChain.Height + if currentHeight < pow.chainParams.DPoSConfiguration.RevertToPOWStartHeight { continue } if pow.arbiters.IsInPOWMode() { @@ -29,9 +30,16 @@ func (pow *Service) ListenForRevert() { } lastBlockTimestamp := int64(pow.arbiters.GetLastBlockTimestamp()) localTimestamp := pow.chain.TimeSource.AdjustedTime().Unix() + var noBlockTime int64 + if currentHeight < pow.chainParams.DPoSConfiguration.RevertToPOWV1Height { + noBlockTime = pow.chainParams.DPoSConfiguration.RevertToPOWNoBlockTime + } else { + noBlockTime = pow.chainParams.DPoSConfiguration.RevertToPOWNoBlockTimeV1 + } + log.Debug("ListenForRevert lastBlockTimestamp:", lastBlockTimestamp, - "localTimestamp:", localTimestamp, "RevertToPOWNoBlockTime:", pow.chainParams.DPoSConfiguration.RevertToPOWNoBlockTime) - if localTimestamp-lastBlockTimestamp < pow.chainParams.DPoSConfiguration.RevertToPOWNoBlockTime { + "localTimestamp:", localTimestamp, "RevertToPOWNoBlockTime:", noBlockTime) + if localTimestamp-lastBlockTimestamp < noBlockTime { continue }