preprepare.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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. package core
  17. import (
  18. "time"
  19. "github.com/ethereum/go-ethereum/common/hexutil"
  20. "github.com/ethereum/go-ethereum/consensus"
  21. qbfttypes "github.com/ethereum/go-ethereum/consensus/istanbul/qbft/types"
  22. "github.com/ethereum/go-ethereum/rlp"
  23. )
  24. // sendPreprepareMsg is called either
  25. // - when we are proposer after calling `miner.Seal(...)`
  26. // - roundChange happens and we are the proposer
  27. // It
  28. // - creates and sign PRE-PREPARE message with block proposed on `miner.Seal()`
  29. // - extends PRE-PREPARE message with ROUND-CHANGE and PREPARE justification
  30. // - broadcast PRE-PREPARE message to other validators
  31. func (c *core) sendPreprepareMsg(request *Request) {
  32. logger := c.currentLogger(true, nil)
  33. // If I'm the proposer and I have the same sequence with the proposal
  34. if c.current.Sequence().Cmp(request.Proposal.Number()) == 0 && c.IsProposer() {
  35. // Creates PRE-PREPARE message
  36. curView := c.currentView()
  37. preprepare := qbfttypes.NewPreprepare(curView.Sequence, curView.Round, request.Proposal)
  38. preprepare.SetSource(c.Address())
  39. // Sign payload
  40. encodedPayload, err := preprepare.EncodePayloadForSigning()
  41. if err != nil {
  42. withMsg(logger, preprepare).Error("QBFT: failed to encode payload of PRE-PREPARE message", "err", err)
  43. return
  44. }
  45. signature, err := c.backend.Sign(encodedPayload)
  46. if err != nil {
  47. withMsg(logger, preprepare).Error("QBFT: failed to sign PRE-PREPARE message", "err", err)
  48. return
  49. }
  50. preprepare.SetSignature(signature)
  51. // Extend PRE-PREPARE message with ROUND-CHANGE justification
  52. if request.RCMessages != nil {
  53. preprepare.JustificationRoundChanges = make([]*qbfttypes.SignedRoundChangePayload, 0)
  54. for _, m := range request.RCMessages.Values() {
  55. preprepare.JustificationRoundChanges = append(preprepare.JustificationRoundChanges, &m.(*qbfttypes.RoundChange).SignedRoundChangePayload)
  56. withMsg(logger, preprepare).Trace("QBFT: add ROUND-CHANGE justification", "rc", m.(*qbfttypes.RoundChange).SignedRoundChangePayload)
  57. }
  58. withMsg(logger, preprepare).Trace("QBFT: extended PRE-PREPARE message with ROUND-CHANGE justifications", "justifications", preprepare.JustificationRoundChanges)
  59. }
  60. // Extend PRE-PREPARE message with PREPARE justification
  61. if request.PrepareMessages != nil {
  62. preprepare.JustificationPrepares = request.PrepareMessages
  63. withMsg(logger, preprepare).Trace("QBFT: extended PRE-PREPARE message with PREPARE justification", "justification", preprepare.JustificationPrepares)
  64. }
  65. // RLP-encode message
  66. payload, err := rlp.EncodeToBytes(&preprepare)
  67. if err != nil {
  68. withMsg(logger, preprepare).Error("QBFT: failed to encode PRE-PREPARE message", "err", err)
  69. return
  70. }
  71. logger = withMsg(logger, preprepare).New("block.number", preprepare.Proposal.Number().Uint64(), "block.hash", preprepare.Proposal.Hash().String())
  72. logger.Info("QBFT: broadcast PRE-PREPARE message", "payload", hexutil.Encode(payload))
  73. // Broadcast RLP-encoded message
  74. if err = c.backend.Broadcast(c.valSet, preprepare.Code(), payload); err != nil {
  75. logger.Error("QBFT: failed to broadcast PRE-PREPARE message", "err", err)
  76. return
  77. }
  78. // Set the preprepareSent to the current round
  79. c.current.preprepareSent = curView.Round
  80. }
  81. }
  82. // handlePreprepareMsg is called when receiving a PRE-PREPARE message from the proposer
  83. // It
  84. // - validates PRE-PREPARE message was created by the right proposer node
  85. // - validates PRE-PREPARE message justification
  86. // - validates PRE-PREPARE message block proposal
  87. func (c *core) handlePreprepareMsg(preprepare *qbfttypes.Preprepare) error {
  88. logger := c.currentLogger(true, preprepare)
  89. logger = logger.New("proposal.number", preprepare.Proposal.Number().Uint64(), "proposal.hash", preprepare.Proposal.Hash().String())
  90. c.logger.Info("QBFT: handle PRE-PREPARE message")
  91. // Validates PRE-PREPARE message comes from current proposer
  92. if !c.valSet.IsProposer(preprepare.Source()) {
  93. logger.Warn("QBFT: ignore PRE-PREPARE message from non proposer", "proposer", c.valSet.GetProposer().Address())
  94. return errNotFromProposer
  95. }
  96. // Validates PRE-PREPARE message justification
  97. if preprepare.Round.Uint64() > 0 {
  98. if err := isJustified(preprepare.Proposal, preprepare.JustificationRoundChanges, preprepare.JustificationPrepares, c.QuorumSize()); err != nil {
  99. logger.Warn("QBFT: invalid PRE-PREPARE message justification", "err", err)
  100. return errInvalidPreparedBlock
  101. }
  102. }
  103. // Validates PRE-PREPARE block proposal we received
  104. if duration, err := c.backend.Verify(preprepare.Proposal); err != nil {
  105. // if it's a future block, we will handle it again after the duration
  106. if err == consensus.ErrFutureBlock {
  107. logger.Info("QBFT: PRE-PREPARE block proposal is in the future (will be treated again later)", "duration", duration)
  108. // start a timer to re-input PRE-PREPARE message as a backlog event
  109. c.stopFuturePreprepareTimer()
  110. c.futurePreprepareTimer = time.AfterFunc(duration, func() {
  111. _, validator := c.valSet.GetByAddress(preprepare.Source())
  112. c.sendEvent(backlogEvent{
  113. src: validator,
  114. msg: preprepare,
  115. })
  116. })
  117. } else {
  118. logger.Warn("QBFT: invalid PRE-PREPARE block proposal", "err", err)
  119. }
  120. return err
  121. }
  122. // Here is about to accept the PRE-PREPARE
  123. if c.state == StateAcceptRequest {
  124. c.logger.Info("QBFT: accepted PRE-PREPARE message")
  125. // Re-initialize ROUND-CHANGE timer
  126. c.newRoundChangeTimer()
  127. c.consensusTimestamp = time.Now()
  128. // Update current state
  129. c.current.SetPreprepare(preprepare)
  130. c.setState(StatePreprepared)
  131. // Broadcast prepare message to other validators
  132. c.broadcastPrepare()
  133. }
  134. return nil
  135. }