commit.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  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. "reflect"
  19. "github.com/ethereum/go-ethereum/common"
  20. "github.com/ethereum/go-ethereum/consensus/istanbul"
  21. istanbulcommon "github.com/ethereum/go-ethereum/consensus/istanbul/common"
  22. ibfttypes "github.com/ethereum/go-ethereum/consensus/istanbul/ibft/types"
  23. )
  24. func (c *core) sendCommit() {
  25. sub := c.current.Subject()
  26. c.broadcastCommit(sub)
  27. }
  28. func (c *core) sendCommitForOldBlock(view *istanbul.View, digest common.Hash) {
  29. sub := &istanbul.Subject{
  30. View: view,
  31. Digest: digest,
  32. }
  33. c.broadcastCommit(sub)
  34. }
  35. func (c *core) broadcastCommit(sub *istanbul.Subject) {
  36. logger := c.logger.New("state", c.state)
  37. encodedSubject, err := ibfttypes.Encode(sub)
  38. if err != nil {
  39. logger.Error("Failed to encode", "subject", sub)
  40. return
  41. }
  42. c.broadcast(&ibfttypes.Message{
  43. Code: ibfttypes.MsgCommit,
  44. Msg: encodedSubject,
  45. })
  46. }
  47. func (c *core) handleCommit(msg *ibfttypes.Message, src istanbul.Validator) error {
  48. // Decode COMMIT message
  49. var commit *istanbul.Subject
  50. err := msg.Decode(&commit)
  51. if err != nil {
  52. return istanbulcommon.ErrFailedDecodeCommit
  53. }
  54. if err := c.checkMessage(ibfttypes.MsgCommit, commit.View); err != nil {
  55. return err
  56. }
  57. if err := c.verifyCommit(commit, src); err != nil {
  58. return err
  59. }
  60. c.acceptCommit(msg, src)
  61. // Commit the proposal once we have enough COMMIT messages and we are not in the Committed state.
  62. //
  63. // If we already have a proposal, we may have chance to speed up the consensus process
  64. // by committing the proposal without PREPARE messages.
  65. if c.current.Commits.Size() >= c.QuorumSize() && c.state.Cmp(ibfttypes.StateCommitted) < 0 {
  66. // Still need to call LockHash here since state can skip Prepared state and jump directly to the Committed state.
  67. c.current.LockHash()
  68. c.commit()
  69. }
  70. return nil
  71. }
  72. // verifyCommit verifies if the received COMMIT message is equivalent to our subject
  73. func (c *core) verifyCommit(commit *istanbul.Subject, src istanbul.Validator) error {
  74. logger := c.logger.New("from", src, "state", c.state)
  75. sub := c.current.Subject()
  76. if !reflect.DeepEqual(commit, sub) {
  77. logger.Warn("Inconsistent subjects between commit and proposal", "expected", sub, "got", commit)
  78. return istanbulcommon.ErrInconsistentSubject
  79. }
  80. return nil
  81. }
  82. func (c *core) acceptCommit(msg *ibfttypes.Message, src istanbul.Validator) error {
  83. logger := c.logger.New("from", src, "state", c.state)
  84. // Add the COMMIT message to current round state
  85. if err := c.current.Commits.Add(msg); err != nil {
  86. logger.Error("Failed to record commit message", "msg", msg, "err", err)
  87. return err
  88. }
  89. return nil
  90. }