github.com/elastos/Elastos.ELA.SideChain.ETH@v0.2.2/dpos/consensusview.go (about) 1 // Copyright (c) 2017-2019 The Elastos Foundation 2 // Use of this source code is governed by an MIT 3 // license that can be found in the LICENSE file. 4 // 5 6 package dpos 7 8 import ( 9 "bytes" 10 "sort" 11 "time" 12 13 "github.com/elastos/Elastos.ELA/common" 14 "github.com/elastos/Elastos.ELA/common/log" 15 "github.com/elastos/Elastos.ELA/dpos/p2p/peer" 16 ) 17 18 type ViewListener interface { 19 OnViewChanged(isOnDuty bool, force bool) 20 } 21 22 const ( 23 ConsensusReady = iota 24 ConsensusRunning 25 ) 26 27 type ConsensusView struct { 28 consensusStatus uint32 29 viewOffset uint32 30 publicKey []byte 31 signTolerance time.Duration 32 viewStartTime time.Time 33 viewChangeTime time.Time 34 isDposOnDuty bool 35 producers *Producers 36 37 listener ViewListener 38 } 39 40 func (v *ConsensusView) resetViewOffset() { 41 v.viewOffset = 0 42 } 43 44 func (v *ConsensusView) SetRunning() { 45 v.consensusStatus = ConsensusRunning 46 } 47 48 func (v *ConsensusView) SetReady() { 49 v.consensusStatus = ConsensusReady 50 } 51 52 func (v *ConsensusView) IsRunning() bool { 53 return v.consensusStatus == ConsensusRunning 54 } 55 56 func (v *ConsensusView) IsReady() bool { 57 return v.consensusStatus == ConsensusReady 58 } 59 60 func (v *ConsensusView) TryChangeView(now time.Time) { 61 if v.IsRunning() && now.After(v.viewChangeTime) { 62 Info("[TryChangeView] succeed", "now", now.String(), "changeTime", v.viewChangeTime.String()) 63 parentTime := float64(v.viewChangeTime.Unix()) - v.signTolerance.Seconds() 64 v.ChangeView(now, false, uint64(parentTime)) 65 } 66 } 67 68 func (v *ConsensusView) GetProducers() [][]byte { 69 return v.producers.GetProducers() 70 } 71 72 func (v *ConsensusView) GetTotalArbiterCount() int { 73 return v.producers.totalProducers 74 } 75 76 func (v *ConsensusView) GetSpvHeight() uint64 { 77 return v.producers.spvHeight 78 } 79 80 func (v *ConsensusView) GetTotalProducersCount() int { 81 return v.producers.totalProducers 82 } 83 84 func (v *ConsensusView) UpdateProducers(producers [][]byte, totalCount int, spvHeight uint64) { 85 sort.Slice(producers, func(i, j int) bool { 86 return bytes.Compare(producers[i], producers[j]) < 0 87 }) 88 v.producers.UpdateProducers(producers, totalCount, spvHeight) 89 } 90 91 func (v *ConsensusView) ChangeCurrentProducers(changeHeight uint64, spvHeight uint64) { 92 v.producers.ChangeCurrentProducers(changeHeight, spvHeight) 93 } 94 95 func (v *ConsensusView) ProducerIndex(signer []byte) int { 96 if len(signer) <= 0 { 97 return -1 98 } 99 return v.producers.ProducerIndex(signer) 100 } 101 102 func (v *ConsensusView) SetWorkingHeight(workingHeight uint64) { 103 v.producers.SetWorkingHeight(workingHeight) 104 } 105 106 func (v *ConsensusView) getCurrentNeedConnectArbiters() []peer.PID { 107 return v.producers.getCurrentNeedConnectArbiters() 108 } 109 110 func (v *ConsensusView) GetNextNeedConnectArbiters() []peer.PID { 111 return v.producers.GetNextNeedConnectArbiters() 112 } 113 114 func (v *ConsensusView) UpdateNextProducers(producers []peer.PID, totalCount int) { 115 v.producers.UpdateNextProducers(producers, totalCount) 116 } 117 118 func (v *ConsensusView) IsSameProducers(curProducers [][]byte) bool { 119 v.producers.mtx.Lock() 120 defer v.producers.mtx.Unlock() 121 nextProducers := v.producers.nextProducers 122 if len(curProducers) != len(nextProducers) { 123 return false 124 } 125 sort.Slice(nextProducers, func(i, j int) bool { 126 return bytes.Compare(nextProducers[i][:], nextProducers[j][:]) < 0 127 }) 128 129 sort.Slice(curProducers, func(i, j int) bool { 130 return bytes.Compare(curProducers[i], curProducers[j]) < 0 131 }) 132 133 for index, v := range curProducers { 134 if !bytes.Equal(v, nextProducers[index][:]) { 135 return false 136 } 137 } 138 return true 139 } 140 141 func (v *ConsensusView) IsCurrentProducers(curProducers [][]byte) bool { 142 v.producers.mtx.Lock() 143 defer v.producers.mtx.Unlock() 144 producers := v.producers.producers 145 if len(producers) <= 0 { 146 return false 147 } 148 if len(curProducers) != len(producers) { 149 return false 150 } 151 sort.Slice(producers, func(i, j int) bool { 152 return bytes.Compare(producers[i][:], producers[j][:]) < 0 153 }) 154 155 sort.Slice(curProducers, func(i, j int) bool { 156 return bytes.Compare(curProducers[i], curProducers[j]) < 0 157 }) 158 159 for index, v := range curProducers { 160 if !bytes.Equal(v, producers[index][:]) { 161 return false 162 } 163 } 164 return true 165 } 166 167 func (v *ConsensusView) calculateOffsetTime(startTime time.Time, 168 now time.Time) (uint32, time.Duration) { 169 duration := now.Sub(startTime) 170 offset := duration / v.signTolerance 171 offsetTime := duration % v.signTolerance 172 173 return uint32(offset), offsetTime 174 } 175 176 func (v *ConsensusView) UpdateDutyIndex(height uint64) { 177 v.producers.UpdateDutyIndex(height) 178 179 currentProducer := v.producers.GetNextOnDutyProducer(v.viewOffset) 180 v.isDposOnDuty = bytes.Equal(currentProducer, v.publicKey) 181 } 182 183 func (v *ConsensusView) ChangeView(now time.Time, force bool, parentTime uint64) { 184 offset, offsetTime := v.calculateOffsetTime(v.viewStartTime, now) 185 if offset > 0 { 186 v.viewStartTime = now.Add(-offsetTime) 187 v.ResetView(uint64(v.viewStartTime.Unix())) 188 } 189 v.viewOffset += offset 190 if force { 191 offset = 1 192 v.resetViewOffset() 193 v.ResetView(parentTime) 194 } 195 196 if offset > 0 { 197 Info("\n\n\n--------------------Change View---------------------") 198 Info("viewStartTime:", v.viewStartTime, "changeViewTime", v.viewChangeTime, "nowTime:", now, "offset:", offset, "offsetTime:", offsetTime, "force:", force, 199 "viewOffset", v.viewOffset, "dutyIndex", v.producers.dutyIndex) 200 currentProducer := v.producers.GetNextOnDutyProducer(v.viewOffset) 201 v.isDposOnDuty = bytes.Equal(currentProducer, v.publicKey) 202 v.DumpInfo() 203 Info("\n\n\n") 204 if v.listener != nil { 205 v.listener.OnViewChanged(v.isDposOnDuty, force) 206 } 207 } 208 } 209 210 func (v *ConsensusView) DumpInfo() { 211 str := "\n" 212 for _, signer := range v.producers.producers { 213 if v.ProducerIsOnDuty(signer) { 214 duty := log.Color(log.Green, common.BytesToHexString(signer)+" onDuty \n") 215 str = str + duty 216 } else { 217 str = str + common.BytesToHexString(signer) + " not onDuty \n" 218 } 219 } 220 Info(str) 221 } 222 223 func (v *ConsensusView) GetViewInterval() time.Duration { 224 return v.signTolerance 225 } 226 227 func (v *ConsensusView) GetViewStartTime() time.Time { 228 return v.viewStartTime 229 } 230 231 func (v *ConsensusView) GetChangeViewTime() time.Time { 232 return v.viewChangeTime 233 } 234 235 func (v *ConsensusView) GetDutyIndex() uint32 { 236 return v.producers.dutyIndex 237 } 238 239 func (v *ConsensusView) GetViewOffset() uint32 { 240 return v.viewOffset 241 } 242 243 func (v *ConsensusView) ResetView(parentTime uint64) { 244 v.SetChangViewTime(parentTime) 245 } 246 247 func (v *ConsensusView) SetChangViewTime(parentTime uint64) { 248 headerTime := time.Unix(int64(parentTime), 0) 249 v.viewChangeTime = headerTime.Add(v.signTolerance) 250 v.viewStartTime = headerTime 251 } 252 253 func (v *ConsensusView) IsProducers(account []byte) bool { 254 return v.producers.IsProducers(account) 255 } 256 257 func (v *ConsensusView) IsOnduty() bool { 258 return v.isDposOnDuty 259 } 260 261 func (v *ConsensusView) ProducerIsOnDuty(account []byte) bool { 262 producer := v.producers.GetNextOnDutyProducer(v.viewOffset) 263 return bytes.Equal(producer, account) 264 } 265 266 func (v *ConsensusView) IsMajorityAgree(count int) bool { 267 return v.producers.IsMajorityAgree(count) 268 } 269 270 func (v *ConsensusView) IsMajorityRejected(count int) bool { 271 return v.producers.IsMajorityRejected(count) 272 } 273 274 func (v *ConsensusView) HasArbitersMinorityCount(count int) bool { 275 return v.producers.HasArbitersMinorityCount(count) 276 } 277 278 func (v *ConsensusView) HasProducerMajorityCount(count int) bool { 279 return v.producers.HasProducerMajorityCount(count) 280 } 281 282 func (v *ConsensusView) GetMajorityCount() int { 283 return v.producers.GetMajorityCount() 284 } 285 286 func (v *ConsensusView) GetCRMajorityCount() int { 287 return v.producers.GetCRMajorityCount() 288 } 289 290 func (v *ConsensusView) GetMajorityCountByTotalSigners(totalSigner int) int { 291 return v.producers.GetMajorityCountByTotalSigners(totalSigner) 292 } 293 294 func NewConsensusView(tolerance time.Duration, account []byte, 295 producers *Producers, viewListener ViewListener) *ConsensusView { 296 c := &ConsensusView{ 297 consensusStatus: ConsensusReady, 298 viewStartTime: time.Unix(0, 0), 299 viewOffset: 0, 300 publicKey: account, 301 signTolerance: tolerance, 302 producers: producers, 303 listener: viewListener, 304 isDposOnDuty: false, 305 } 306 return c 307 }