github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/consensus/istanbul/core/core.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "bytes" 21 "fmt" 22 "math" 23 "math/big" 24 "sync" 25 "time" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/common/prque" 29 "github.com/ethereum/go-ethereum/consensus" 30 "github.com/ethereum/go-ethereum/consensus/istanbul" 31 "github.com/ethereum/go-ethereum/consensus/istanbul/validator" 32 "github.com/ethereum/go-ethereum/core/types" 33 blscrypto "github.com/ethereum/go-ethereum/crypto/bls" 34 "github.com/ethereum/go-ethereum/event" 35 "github.com/ethereum/go-ethereum/log" 36 "github.com/ethereum/go-ethereum/metrics" 37 "github.com/syndtr/goleveldb/leveldb" 38 ) 39 40 type core struct { 41 config *istanbul.Config 42 address common.Address 43 logger log.Logger 44 selectProposer istanbul.ProposerSelector 45 46 backend istanbul.Backend 47 events *event.TypeMuxSubscription 48 finalCommittedSub *event.TypeMuxSubscription 49 timeoutSub *event.TypeMuxSubscription 50 51 futurePreprepareTimer *time.Timer 52 resendRoundChangeMessageTimer *time.Timer 53 roundChangeTimer *time.Timer 54 55 validateFn func([]byte, []byte) (common.Address, error) 56 57 backlog MsgBacklog 58 59 rsdb RoundStateDB 60 current RoundState 61 handlerWg *sync.WaitGroup 62 63 roundChangeSet *roundChangeSet 64 65 pendingRequests *prque.Prque 66 pendingRequestsMu *sync.Mutex 67 68 consensusTimestamp time.Time 69 // the meter to record the round change rate 70 roundMeter metrics.Meter 71 // the meter to record the sequence update rate 72 sequenceMeter metrics.Meter 73 // the timer to record consensus duration (from accepting a preprepare to final committed stage) 74 consensusTimer metrics.Timer 75 } 76 77 // New creates an Istanbul consensus core 78 func New(backend istanbul.Backend, config *istanbul.Config) Engine { 79 rsdb, err := newRoundStateDB(config.RoundStateDBPath, nil) 80 if err != nil { 81 log.Crit("Failed to open RoundStateDB", "err", err) 82 } 83 84 c := &core{ 85 config: config, 86 address: backend.Address(), 87 logger: log.New(), 88 selectProposer: validator.GetProposerSelector(config.ProposerPolicy), 89 handlerWg: new(sync.WaitGroup), 90 backend: backend, 91 pendingRequests: prque.New(nil), 92 pendingRequestsMu: new(sync.Mutex), 93 consensusTimestamp: time.Time{}, 94 rsdb: rsdb, 95 roundMeter: metrics.NewRegisteredMeter("consensus/istanbul/core/round", nil), 96 sequenceMeter: metrics.NewRegisteredMeter("consensus/istanbul/core/sequence", nil), 97 consensusTimer: metrics.NewRegisteredTimer("consensus/istanbul/core/consensus", nil), 98 } 99 msgBacklog := newMsgBacklog( 100 func(msg *istanbul.Message) { 101 c.sendEvent(backlogEvent{ 102 msg: msg, 103 }) 104 }, c.checkMessage) 105 c.backlog = msgBacklog 106 c.validateFn = c.checkValidatorSignature 107 c.logger = istanbul.NewIstLogger( 108 func() *big.Int { 109 if c != nil && c.current != nil { 110 return c.current.Round() 111 } 112 return common.Big0 113 }, 114 ) 115 return c 116 } 117 118 // ---------------------------------------------------------------------------- 119 120 func (c *core) SetAddress(address common.Address) { 121 c.address = address 122 c.logger = log.New("address", address) 123 } 124 125 func (c *core) CurrentView() *istanbul.View { 126 if c.current == nil { 127 return nil 128 } 129 return c.current.View() 130 } 131 132 func (c *core) CurrentRoundState() RoundState { return c.current } 133 134 func (c *core) ParentCommits() MessageSet { 135 if c.current == nil { 136 return nil 137 } 138 return c.current.ParentCommits() 139 } 140 141 func (c *core) ForceRoundChange() { 142 // timeout current DesiredView 143 view := &istanbul.View{Sequence: c.current.Sequence(), Round: c.current.DesiredRound()} 144 c.sendEvent(timeoutAndMoveToNextRoundEvent{view}) 145 } 146 147 // PrepareCommittedSeal returns a committed seal for the given hash and round number. 148 func PrepareCommittedSeal(hash common.Hash, round *big.Int) []byte { 149 var buf bytes.Buffer 150 buf.Write(hash.Bytes()) 151 buf.Write(round.Bytes()) 152 buf.Write([]byte{byte(istanbul.MsgCommit)}) 153 return buf.Bytes() 154 } 155 156 // GetAggregatedSeal aggregates all the given seals for a given message set to a bls aggregated 157 // signature and bitmap 158 func GetAggregatedSeal(seals MessageSet, round *big.Int) (types.IstanbulAggregatedSeal, error) { 159 bitmap := big.NewInt(0) 160 committedSeals := make([][]byte, seals.Size()) 161 for i, v := range seals.Values() { 162 committedSeals[i] = make([]byte, types.IstanbulExtraBlsSignature) 163 164 var commit *istanbul.CommittedSubject 165 err := v.Decode(&commit) 166 if err != nil { 167 return types.IstanbulAggregatedSeal{}, err 168 } 169 copy(committedSeals[i][:], commit.CommittedSeal[:]) 170 171 j, err := seals.GetAddressIndex(v.Address) 172 if err != nil { 173 return types.IstanbulAggregatedSeal{}, err 174 } 175 bitmap.SetBit(bitmap, int(j), 1) 176 } 177 178 asig, err := blscrypto.AggregateSignatures(committedSeals) 179 if err != nil { 180 return types.IstanbulAggregatedSeal{}, err 181 } 182 return types.IstanbulAggregatedSeal{Bitmap: bitmap, Signature: asig, Round: round}, nil 183 } 184 185 // UnionOfSeals combines a BLS aggregated signature with an array of signatures. Accounts for 186 // double aggregating the same signature by only adding aggregating if the 187 // validator was not found in the previous bitmap. 188 // This function assumes that the provided seals' validator set is the same one 189 // which produced the provided bitmap 190 func UnionOfSeals(aggregatedSignature types.IstanbulAggregatedSeal, seals MessageSet) (types.IstanbulAggregatedSeal, error) { 191 // TODO(asa): Check for round equality... 192 // Check who already has signed the message 193 newBitmap := new(big.Int).Set(aggregatedSignature.Bitmap) 194 committedSeals := [][]byte{} 195 committedSeals = append(committedSeals, aggregatedSignature.Signature) 196 for _, v := range seals.Values() { 197 valIndex, err := seals.GetAddressIndex(v.Address) 198 if err != nil { 199 return types.IstanbulAggregatedSeal{}, err 200 } 201 202 var commit *istanbul.CommittedSubject 203 err = v.Decode(&commit) 204 if err != nil { 205 return types.IstanbulAggregatedSeal{}, err 206 } 207 208 // if the bit was not set, this means we should add this signature to 209 // the batch 210 if newBitmap.Bit(int(valIndex)) == 0 { 211 newBitmap.SetBit(newBitmap, (int(valIndex)), 1) 212 committedSeals = append(committedSeals, commit.CommittedSeal) 213 } 214 } 215 216 asig, err := blscrypto.AggregateSignatures(committedSeals) 217 if err != nil { 218 return types.IstanbulAggregatedSeal{}, err 219 } 220 221 return types.IstanbulAggregatedSeal{ 222 Bitmap: newBitmap, 223 Signature: asig, 224 Round: aggregatedSignature.Round, 225 }, nil 226 } 227 228 // Appends the current view and state to the given context. 229 func (c *core) newLogger(ctx ...interface{}) log.Logger { 230 var seq, round, desired *big.Int 231 var state State 232 if c.current != nil { 233 state = c.current.State() 234 seq = c.current.Sequence() 235 round = c.current.Round() 236 desired = c.current.DesiredRound() 237 } else { 238 seq = common.Big0 239 round = big.NewInt(-1) 240 desired = big.NewInt(-1) 241 } 242 logger := c.logger.New(ctx...) 243 return logger.New("cur_seq", seq, "cur_round", round, "desired_round", desired, "state", state, "address", c.address) 244 } 245 246 func (c *core) finalizeMessage(msg *istanbul.Message) ([]byte, error) { 247 // Add sender address 248 msg.Address = c.address 249 250 if err := msg.Sign(c.backend.Sign); err != nil { 251 return nil, err 252 } 253 254 // Convert to payload 255 payload, err := msg.Payload() 256 if err != nil { 257 return nil, err 258 } 259 260 return payload, nil 261 } 262 263 // Send message to all current validators 264 func (c *core) broadcast(msg *istanbul.Message) { 265 c.sendMsgTo(msg, istanbul.MapValidatorsToAddresses(c.current.ValidatorSet().List())) 266 } 267 268 // Send message to a specific address 269 func (c *core) unicast(msg *istanbul.Message, addr common.Address) { 270 c.sendMsgTo(msg, []common.Address{addr}) 271 } 272 273 func (c *core) sendMsgTo(msg *istanbul.Message, addresses []common.Address) { 274 logger := c.newLogger("func", "sendMsgTo") 275 276 payload, err := c.finalizeMessage(msg) 277 if err != nil { 278 logger.Error("Failed to finalize message", "m", msg, "err", err) 279 return 280 } 281 282 // Send payload to the specified addresses 283 if err := c.backend.BroadcastConsensusMsg(addresses, payload); err != nil { 284 logger.Error("Failed to send message", "m", msg, "err", err) 285 return 286 } 287 } 288 289 func (c *core) commit() error { 290 err := c.current.TransitionToCommitted() 291 if err != nil { 292 return err 293 } 294 295 // Process Backlog Messages 296 c.backlog.updateState(c.current.View(), c.current.State()) 297 298 proposal := c.current.Proposal() 299 if proposal != nil { 300 aggregatedSeal, err := GetAggregatedSeal(c.current.Commits(), c.current.Round()) 301 if err != nil { 302 nextRound := new(big.Int).Add(c.current.Round(), common.Big1) 303 c.logger.Warn("Error on commit, waiting for desired round", "reason", "getAggregatedSeal", "err", err, "desired_round", nextRound) 304 c.waitForDesiredRound(nextRound) 305 return nil 306 } 307 aggregatedEpochValidatorSetSeal, err := GetAggregatedEpochValidatorSetSeal(c.current.Commits()) 308 if err != nil { 309 nextRound := new(big.Int).Add(c.current.Round(), common.Big1) 310 c.logger.Warn("Error on commit, waiting for desired round", "reason", "GetAggregatedEpochValidatorSetSeal", "err", err, "desired_round", nextRound) 311 c.waitForDesiredRound(nextRound) 312 return nil 313 } 314 if err := c.backend.Commit(proposal, aggregatedSeal, aggregatedEpochValidatorSetSeal); err != nil { 315 nextRound := new(big.Int).Add(c.current.Round(), common.Big1) 316 c.logger.Warn("Error on commit, waiting for desired round", "reason", "backend.Commit", "err", err, "desired_round", nextRound) 317 c.waitForDesiredRound(nextRound) 318 return nil 319 } 320 } 321 return nil 322 } 323 324 // GetAggregatedEpochValidatorSetSeal aggregates all the given seals for the SNARK-friendly epoch encoding 325 // to a bls aggregated signature 326 func GetAggregatedEpochValidatorSetSeal(seals MessageSet) (types.IstanbulEpochValidatorSetSeal, error) { 327 epochSeals := make([][]byte, seals.Size()) 328 for i, v := range seals.Values() { 329 epochSeals[i] = make([]byte, types.IstanbulExtraBlsSignature) 330 331 var commit *istanbul.CommittedSubject 332 err := v.Decode(&commit) 333 if err != nil { 334 return types.IstanbulEpochValidatorSetSeal{}, err 335 } 336 copy(epochSeals[i], commit.EpochValidatorSetSeal[:]) 337 } 338 339 asig, err := blscrypto.AggregateSignatures(epochSeals) 340 if err != nil { 341 return types.IstanbulEpochValidatorSetSeal{}, err 342 } 343 return types.IstanbulEpochValidatorSetSeal{Signature: asig}, nil 344 } 345 346 // Generates the next preprepare request and associated round change certificate 347 func (c *core) getPreprepareWithRoundChangeCertificate(round *big.Int) (*istanbul.Request, istanbul.RoundChangeCertificate, error) { 348 logger := c.newLogger("func", "getPreprepareWithRoundChangeCertificate", "for_round", round) 349 350 roundChangeCertificate, err := c.roundChangeSet.getCertificate(round, c.current.ValidatorSet().MinQuorumSize()) 351 if err != nil { 352 return &istanbul.Request{}, istanbul.RoundChangeCertificate{}, err 353 } 354 // Start with pending request 355 request := c.current.PendingRequest() 356 // Search for a valid request in round change messages. 357 // The proposal must come from the prepared certificate with the highest round number. 358 // All prepared certificates from the same round are assumed to be the same proposal or no proposal (guaranteed by quorum intersection) 359 maxRound := big.NewInt(-1) 360 for _, message := range roundChangeCertificate.RoundChangeMessages { 361 var roundChangeMsg *istanbul.RoundChange 362 if err := message.Decode(&roundChangeMsg); err != nil { 363 logger.Error("Unexpected: could not decode a previously received RoundChange message") 364 return &istanbul.Request{}, istanbul.RoundChangeCertificate{}, err 365 } 366 367 if !roundChangeMsg.HasPreparedCertificate() { 368 continue 369 } 370 371 preparedCertificateView, err := c.getViewFromVerifiedPreparedCertificate(roundChangeMsg.PreparedCertificate) 372 if err != nil { 373 logger.Error("Unexpected: could not verify a previously received PreparedCertificate message", "src_m", message) 374 return &istanbul.Request{}, istanbul.RoundChangeCertificate{}, err 375 } 376 377 if preparedCertificateView != nil && preparedCertificateView.Round.Cmp(maxRound) > 0 { 378 maxRound = preparedCertificateView.Round 379 request = &istanbul.Request{ 380 Proposal: roundChangeMsg.PreparedCertificate.Proposal, 381 } 382 } 383 } 384 return request, roundChangeCertificate, nil 385 } 386 387 // startNewRound starts a new round. if round equals to 0, it means to starts a new sequence 388 func (c *core) startNewRound(round *big.Int) error { 389 logger := c.newLogger("func", "startNewRound", "tag", "stateTransition") 390 391 roundChange := false 392 // Try to get last proposal 393 headBlock, headAuthor := c.backend.GetCurrentHeadBlockAndAuthor() 394 395 if headBlock.Number().Cmp(c.current.Sequence()) >= 0 { 396 // Want to be working on the block 1 beyond the last committed block. 397 diff := new(big.Int).Sub(headBlock.Number(), c.current.Sequence()) 398 c.sequenceMeter.Mark(new(big.Int).Add(diff, common.Big1).Int64()) 399 400 if !c.consensusTimestamp.IsZero() { 401 c.consensusTimer.UpdateSince(c.consensusTimestamp) 402 c.consensusTimestamp = time.Time{} 403 } 404 logger.Trace("Catch up to the latest proposal.", "number", headBlock.Number().Uint64(), "hash", headBlock.Hash()) 405 } else if headBlock.Number().Cmp(big.NewInt(c.current.Sequence().Int64()-1)) == 0 { 406 // Working on the block immediately after the last committed block. 407 if round.Cmp(c.current.Round()) == 0 { 408 logger.Trace("Already in the desired round.") 409 return nil 410 } else if round.Cmp(c.current.Round()) < 0 { 411 logger.Warn("New round should not be smaller than current round", "lastBlockNumber", headBlock.Number().Int64(), "new_round", round) 412 return nil 413 } 414 roundChange = true 415 } else { 416 logger.Warn("New sequence should be larger than current sequence", "new_seq", headBlock.Number().Int64()) 417 return nil 418 } 419 420 // Generate next view and preprepare 421 var newView *istanbul.View 422 var roundChangeCertificate istanbul.RoundChangeCertificate 423 var request *istanbul.Request 424 425 valSet := c.current.ValidatorSet() 426 if roundChange { 427 newView = &istanbul.View{ 428 Sequence: new(big.Int).Set(c.current.Sequence()), 429 Round: new(big.Int).Set(round), 430 } 431 432 var err error 433 request, roundChangeCertificate, err = c.getPreprepareWithRoundChangeCertificate(round) 434 if err != nil { 435 logger.Error("Unable to produce round change certificate", "err", err, "new_round", round) 436 return nil 437 } 438 } else { 439 request = c.current.PendingRequest() 440 newView = &istanbul.View{ 441 Sequence: new(big.Int).Add(headBlock.Number(), common.Big1), 442 Round: new(big.Int), 443 } 444 valSet = c.backend.Validators(headBlock) 445 c.roundChangeSet = newRoundChangeSet(valSet) 446 } 447 448 logger = logger.New("old_proposer", c.current.Proposer()) 449 450 // Calculate new proposer 451 nextProposer := c.selectProposer(valSet, headAuthor, newView.Round.Uint64()) 452 err := c.resetRoundState(newView, valSet, nextProposer, roundChange) 453 454 if err != nil { 455 return err 456 } 457 458 // Process backlog 459 c.processPendingRequests() 460 c.backlog.updateState(c.current.View(), c.current.State()) 461 462 if roundChange && c.isProposer() && request != nil { 463 c.sendPreprepare(request, roundChangeCertificate) 464 } 465 c.resetRoundChangeTimer() 466 467 logger.Debug("New round", "new_round", newView.Round, "new_seq", newView.Sequence, "new_proposer", c.current.Proposer(), "valSet", c.current.ValidatorSet().List(), "size", c.current.ValidatorSet().Size(), "isProposer", c.isProposer()) 468 return nil 469 } 470 471 // All actions that occur when transitioning to waiting for round change state. 472 func (c *core) waitForDesiredRound(r *big.Int) error { 473 logger := c.newLogger("func", "waitForDesiredRound", "old_desired_round", c.current.DesiredRound(), "new_desired_round", r) 474 475 // Don't wait for an older round 476 if c.current.DesiredRound().Cmp(r) >= 0 { 477 logger.Trace("New desired round not greater than current desired round") 478 return nil 479 } 480 481 logger.Debug("Round Change: Waiting for desired round") 482 483 // Perform all of the updates 484 _, headAuthor := c.backend.GetCurrentHeadBlockAndAuthor() 485 nextProposer := c.selectProposer(c.current.ValidatorSet(), headAuthor, r.Uint64()) 486 err := c.current.TransitionToWaitingForNewRound(r, nextProposer) 487 if err != nil { 488 return err 489 } 490 491 c.resetRoundChangeTimer() 492 493 // Process Backlog Messages 494 c.backlog.updateState(c.current.View(), c.current.State()) 495 496 // Send round change 497 c.sendRoundChange() 498 return nil 499 } 500 501 func (c *core) createRoundState() (RoundState, error) { 502 var roundState RoundState 503 504 logger := c.newLogger("func", "createRoundState") 505 506 if c.current != nil { 507 return nil, fmt.Errorf("BUG? Attempting to Start() core with existing c.current") 508 } 509 510 headBlock, headAuthor := c.backend.GetCurrentHeadBlockAndAuthor() 511 nextSequence := new(big.Int).Add(headBlock.Number(), common.Big1) 512 lastStoredView, err := c.rsdb.GetLastView() 513 514 if err != nil && err != leveldb.ErrNotFound { 515 logger.Error("Failed to fetch lastStoredView", "err", err) 516 return nil, err 517 } 518 519 if err == leveldb.ErrNotFound || lastStoredView.Sequence.Cmp(nextSequence) < 0 { 520 if err == leveldb.ErrNotFound { 521 logger.Info("Creating new RoundState", "reason", "No storedView found") 522 } else { 523 logger.Info("Creating new RoundState", "reason", "old view", "stored_view", lastStoredView, "requested_seq", nextSequence) 524 } 525 valSet := c.backend.Validators(headBlock) 526 proposer := c.selectProposer(valSet, headAuthor, 0) 527 roundState = newRoundState(&istanbul.View{Sequence: nextSequence, Round: common.Big0}, valSet, proposer) 528 } else { 529 logger.Info("Retrieving stored RoundState", "stored_view", lastStoredView, "requested_seq", nextSequence) 530 roundState, err = c.rsdb.GetRoundStateFor(lastStoredView) 531 532 if err != nil { 533 logger.Error("Failed to fetch lastStoredRoundState", "err", err) 534 return nil, err 535 } 536 } 537 538 return withSavingDecorator(c.rsdb, roundState), nil 539 } 540 541 // resetRoundState will modify the RoundState to either start a new round or a new sequence 542 // based on the `roundChange` flag given 543 func (c *core) resetRoundState(view *istanbul.View, validatorSet istanbul.ValidatorSet, nextProposer istanbul.Validator, roundChange bool) error { 544 // TODO(Joshua): Include desired round here. 545 if roundChange { 546 return c.current.StartNewRound(view.Round, validatorSet, nextProposer) 547 } 548 549 // sequence change 550 // TODO remove this when we refactor startNewRound() 551 if view.Round.Cmp(common.Big0) != 0 { 552 c.logger.Crit("BUG: DevError: trying to start a new sequence with round != 0", "wanted_round", view.Round) 553 } 554 555 var newParentCommits MessageSet 556 lastSubject, err := c.backend.LastSubject() 557 if err == nil && c.current.Proposal() != nil && c.current.Proposal().Hash() == lastSubject.Digest && c.current.Round().Cmp(lastSubject.View.Round) == 0 { 558 // When changing sequences, if our current Commit messages match the latest block in the chain 559 // (i.e. they're for the same block hash and round), we use this sequence's commits as the ParentCommits field 560 // in the next round. 561 newParentCommits = c.current.Commits() 562 } else { 563 // Otherwise, we will initialize an empty ParentCommits field with the validator set of the last proposal. 564 headBlock := c.backend.GetCurrentHeadBlock() 565 newParentCommits = newMessageSet(c.backend.ParentBlockValidators(headBlock)) 566 } 567 return c.current.StartNewSequence(view.Sequence, validatorSet, nextProposer, newParentCommits) 568 569 } 570 571 func (c *core) isProposer() bool { 572 if c.current == nil { 573 return false 574 } 575 return c.current.IsProposer(c.address) 576 } 577 578 func (c *core) stopFuturePreprepareTimer() { 579 if c.futurePreprepareTimer != nil { 580 c.futurePreprepareTimer.Stop() 581 c.futurePreprepareTimer = nil 582 } 583 } 584 585 func (c *core) stopRoundChangeTimer() { 586 if c.roundChangeTimer != nil { 587 c.roundChangeTimer.Stop() 588 c.roundChangeTimer = nil 589 } 590 } 591 592 func (c *core) stopResendRoundChangeTimer() { 593 if c.resendRoundChangeMessageTimer != nil { 594 c.resendRoundChangeMessageTimer.Stop() 595 c.resendRoundChangeMessageTimer = nil 596 } 597 } 598 599 func (c *core) stopAllTimers() { 600 c.stopFuturePreprepareTimer() 601 c.stopRoundChangeTimer() 602 c.stopResendRoundChangeTimer() 603 } 604 605 func (c *core) getRoundChangeTimeout() time.Duration { 606 baseTimeout := time.Duration(c.config.RequestTimeout) * time.Millisecond 607 round := c.current.DesiredRound().Uint64() 608 if round == 0 { 609 // timeout for first round takes into account expected block period 610 return baseTimeout + time.Duration(c.config.BlockPeriod)*time.Second 611 } else { 612 // timeout for subsequent rounds adds an exponential backoff. 613 return baseTimeout + time.Duration(math.Pow(2, float64(round)))*time.Duration(c.config.TimeoutBackoffFactor)*time.Millisecond 614 } 615 } 616 617 // Reset then set the timer that causes a timeoutAndMoveToNextRoundEvent to be processed. 618 // This may also reset the timer for the next resendRoundChangeEvent. 619 func (c *core) resetRoundChangeTimer() { 620 // Stop all timers here since all 'resends' happen within the interval of a round's timeout. 621 // (Races are handled anyway by checking the seq and desired round haven't changed between 622 // submitting and processing events). 623 c.stopAllTimers() 624 625 view := &istanbul.View{Sequence: c.current.Sequence(), Round: c.current.DesiredRound()} 626 timeout := c.getRoundChangeTimeout() 627 c.roundChangeTimer = time.AfterFunc(timeout, func() { 628 c.sendEvent(timeoutAndMoveToNextRoundEvent{view}) 629 }) 630 631 if c.current.DesiredRound().Cmp(common.Big1) > 0 { 632 logger := c.newLogger("func", "resetRoundChangeTimer") 633 logger.Info("Reset round change timer", "timeout_ms", timeout/time.Millisecond) 634 } 635 636 c.resetResendRoundChangeTimer() 637 } 638 639 // Reset then, if in StateWaitingForNewRound and on round whose timeout is greater than MinResendRoundChangeTimeout, 640 // set a timer that is at most MaxResendRoundChangeTimeout that causes a resendRoundChangeEvent to be processed. 641 func (c *core) resetResendRoundChangeTimer() { 642 c.stopResendRoundChangeTimer() 643 if c.current.State() == StateWaitingForNewRound { 644 minResendTimeout := time.Duration(c.config.MinResendRoundChangeTimeout) * time.Millisecond 645 resendTimeout := c.getRoundChangeTimeout() / 2 646 if resendTimeout < minResendTimeout { 647 return 648 } 649 maxResendTimeout := time.Duration(c.config.MaxResendRoundChangeTimeout) * time.Millisecond 650 if resendTimeout > maxResendTimeout { 651 resendTimeout = maxResendTimeout 652 } 653 view := &istanbul.View{Sequence: c.current.Sequence(), Round: c.current.DesiredRound()} 654 c.resendRoundChangeMessageTimer = time.AfterFunc(resendTimeout, func() { 655 c.sendEvent(resendRoundChangeEvent{view}) 656 }) 657 } 658 } 659 660 // Rebroadcast RoundChange message for desired round if still in StateWaitingForNewRound. 661 // Do not advance desired round. Then clear/reset timer so we may rebroadcast again. 662 func (c *core) resendRoundChangeMessage() { 663 if c.current.State() == StateWaitingForNewRound { 664 c.sendRoundChange() 665 } 666 c.resetResendRoundChangeTimer() 667 } 668 669 func (c *core) checkValidatorSignature(data []byte, sig []byte) (common.Address, error) { 670 return istanbul.CheckValidatorSignature(c.current.ValidatorSet(), data, sig) 671 } 672 673 func (c *core) verifyProposal(proposal istanbul.Proposal) (time.Duration, error) { 674 logger := c.newLogger("func", "verifyProposal", "proposal", proposal.Hash()) 675 if verificationStatus, isCached := c.current.GetProposalVerificationStatus(proposal.Hash()); isCached { 676 logger.Trace("verification status cache hit", "verificationStatus", verificationStatus) 677 return 0, verificationStatus 678 } else { 679 logger.Trace("verification status cache miss") 680 681 duration, err := c.backend.Verify(proposal) 682 logger.Trace("proposal verify return values", "duration", duration, "err", err) 683 684 // Don't cache the verification status if it's a future block 685 if err != consensus.ErrFutureBlock { 686 c.current.SetProposalVerificationStatus(proposal.Hash(), err) 687 } 688 689 return duration, err 690 } 691 }