commit.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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. "github.com/ethereum/go-ethereum/common/hexutil"
  19. qbfttypes "github.com/ethereum/go-ethereum/consensus/istanbul/qbft/types"
  20. "github.com/ethereum/go-ethereum/core/types"
  21. "github.com/ethereum/go-ethereum/rlp"
  22. )
  23. // broadcastCommit is called when receiving quorum of PREPARE message
  24. // It
  25. // - creates a COMMIT message from current proposal
  26. // - broadcast COMMIT message to other validators
  27. func (c *core) broadcastCommit() {
  28. var err error
  29. logger := c.currentLogger(true, nil)
  30. sub := c.current.Subject()
  31. var header *types.Header
  32. if block, ok := c.current.Proposal().(*types.Block); ok {
  33. header = block.Header()
  34. }
  35. // Create Commit Seal
  36. commitSeal, err := c.backend.SignWithoutHashing(PrepareCommittedSeal(header, uint32(c.currentView().Round.Uint64())))
  37. if err != nil {
  38. logger.Error("QBFT: failed to create COMMIT seal", "sub", sub, "err", err)
  39. return
  40. }
  41. commit := qbfttypes.NewCommit(sub.View.Sequence, sub.View.Round, sub.Digest, commitSeal)
  42. commit.SetSource(c.Address())
  43. // Sign Message
  44. encodedPayload, err := commit.EncodePayloadForSigning()
  45. if err != nil {
  46. withMsg(logger, commit).Error("QBFT: failed to encode payload of COMMIT message", "err", err)
  47. return
  48. }
  49. signature, err := c.backend.Sign(encodedPayload)
  50. if err != nil {
  51. withMsg(logger, commit).Error("QBFT: failed to sign COMMIT message", "err", err)
  52. return
  53. }
  54. commit.SetSignature(signature)
  55. // RLP-encode message
  56. payload, err := rlp.EncodeToBytes(&commit)
  57. if err != nil {
  58. withMsg(logger, commit).Error("QBFT: failed to encode COMMIT message", "err", err)
  59. return
  60. }
  61. withMsg(logger, commit).Info("QBFT: broadcast COMMIT message", "payload", hexutil.Encode(payload))
  62. // Broadcast RLP-encoded message
  63. if err = c.backend.Broadcast(c.valSet, commit.Code(), payload); err != nil {
  64. withMsg(logger, commit).Error("QBFT: failed to broadcast COMMIT message", "err", err)
  65. return
  66. }
  67. }
  68. // handleCommitMsg is called when receiving a COMMIT message from another validator
  69. // It
  70. // - validates COMMIT message digest matches the current block proposal
  71. // - accumulates valid COMMIT messages until reaching quorum
  72. // - when quorum of COMMIT messages is reached then update state and commits
  73. func (c *core) handleCommitMsg(commit *qbfttypes.Commit) error {
  74. logger := c.currentLogger(true, commit)
  75. logger.Info("QBFT: handle COMMIT message", "commits.count", c.current.QBFTCommits.Size(), "quorum", c.QuorumSize())
  76. // Check digest
  77. if commit.Digest != c.current.Proposal().Hash() {
  78. logger.Error("QBFT: invalid COMMIT message digest", "digest", commit.Digest, "proposal", c.current.Proposal().Hash().String())
  79. return errInvalidMessage
  80. }
  81. // Add to received msgs
  82. if err := c.current.QBFTCommits.Add(commit); err != nil {
  83. c.logger.Error("QBFT: failed to save COMMIT message", "err", err)
  84. return err
  85. }
  86. logger = logger.New("commits.count", c.current.QBFTCommits.Size(), "quorum", c.QuorumSize())
  87. // If we reached thresho
  88. if c.current.QBFTCommits.Size() >= c.QuorumSize() {
  89. logger.Info("QBFT: received quorum of COMMIT messages")
  90. c.commitQBFT()
  91. } else {
  92. logger.Debug("QBFT: accepted new COMMIT messages")
  93. }
  94. return nil
  95. }
  96. // commitQBFT is called once quorum of commits is reached
  97. // - computes committedSeals from each received commit messages
  98. // - then commits block proposal to database with committed seals
  99. // - broadcast round change
  100. func (c *core) commitQBFT() {
  101. c.setState(StateCommitted)
  102. proposal := c.current.Proposal()
  103. if proposal != nil {
  104. // Compute committed seals
  105. committedSeals := make([][]byte, c.current.QBFTCommits.Size())
  106. for i, msg := range c.current.QBFTCommits.Values() {
  107. committedSeals[i] = make([]byte, types.IstanbulExtraSeal)
  108. commitMsg := msg.(*qbfttypes.Commit)
  109. copy(committedSeals[i][:], commitMsg.CommitSeal[:])
  110. }
  111. // Commit proposal to database
  112. if err := c.backend.Commit(proposal, committedSeals, c.currentView().Round); err != nil {
  113. c.currentLogger(true, nil).Error("QBFT: error committing proposal", "err", err)
  114. c.broadcastNextRoundChange()
  115. return
  116. }
  117. }
  118. }