github.com/klaytn/klaytn@v1.10.2/consensus/istanbul/core/prepare.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2017 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from quorum/consensus/istanbul/core/prepare.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package core 22 23 import ( 24 "reflect" 25 26 "github.com/klaytn/klaytn/consensus/istanbul" 27 ) 28 29 func (c *core) sendPrepare() { 30 logger := c.logger.NewWith("state", c.state) 31 32 sub := c.current.Subject() 33 prevHash := c.current.Proposal().ParentHash() 34 35 // Do not send message if the owner of the core is not a member of the committee for the `sub.View` 36 if !c.valSet.CheckInSubList(prevHash, sub.View, c.Address()) { 37 return 38 } 39 40 encodedSubject, err := Encode(sub) 41 if err != nil { 42 logger.Error("Failed to encode", "subject", sub) 43 return 44 } 45 46 c.broadcast(&message{ 47 Hash: prevHash, 48 Code: msgPrepare, 49 Msg: encodedSubject, 50 }) 51 } 52 53 func (c *core) handlePrepare(msg *message, src istanbul.Validator) error { 54 // Decode PREPARE message 55 var prepare *istanbul.Subject 56 err := msg.Decode(&prepare) 57 if err != nil { 58 logger.Error("Failed to decode message", "code", msg.Code, "err", err) 59 return errInvalidMessage 60 } 61 62 // logger.Error("call receive prepare","num",prepare.View.Sequence) 63 if err := c.checkMessage(msgPrepare, prepare.View); err != nil { 64 return err 65 } 66 67 // If it is locked, it can only process on the locked block. 68 // Passing verifyPrepare and checkMessage implies it is processing on the locked block since it was verified in the Preprepared state. 69 if err := c.verifyPrepare(prepare, src); err != nil { 70 return err 71 } 72 73 if !c.valSet.CheckInSubList(msg.Hash, prepare.View, src.Address()) { 74 logger.Warn("received an istanbul prepare message from non-committee", 75 "currentSequence", c.current.sequence.Uint64(), "sender", src.Address().String(), "msgView", prepare.View.String()) 76 return errNotFromCommittee 77 } 78 79 c.acceptPrepare(msg, src) 80 81 // Change to Prepared state if we've received enough PREPARE/COMMIT messages or it is locked 82 // and we are in earlier state before Prepared state. 83 // Both of PREPARE and COMMIT messages are counted since the nodes which is hashlocked in 84 // the previous round skip sending PREPARE messages. 85 if c.state.Cmp(StatePrepared) < 0 { 86 if c.current.IsHashLocked() && prepare.Digest == c.current.GetLockedHash() { 87 logger.Warn("received prepare of the hash locked proposal and change state to prepared", "msgType", msgPrepare) 88 c.setState(StatePrepared) 89 c.sendCommit() 90 } else if c.current.GetPrepareOrCommitSize() >= requiredMessageCount(c.valSet) { 91 logger.Info("received a quorum of the messages and change state to prepared", "msgType", msgPrepare, "prepareMsgNum", c.current.Prepares.Size(), "commitMsgNum", c.current.Commits.Size(), "valSet", c.valSet.Size()) 92 c.current.LockHash() 93 c.setState(StatePrepared) 94 c.sendCommit() 95 } 96 } 97 98 return nil 99 } 100 101 // verifyPrepare verifies if the received PREPARE message is equivalent to our subject 102 func (c *core) verifyPrepare(prepare *istanbul.Subject, src istanbul.Validator) error { 103 logger := c.logger.NewWith("from", src, "state", c.state) 104 105 sub := c.current.Subject() 106 if !reflect.DeepEqual(prepare, sub) { 107 logger.Warn("Inconsistent subjects between PREPARE and proposal", "expected", sub, "got", prepare) 108 return errInconsistentSubject 109 } 110 111 return nil 112 } 113 114 func (c *core) acceptPrepare(msg *message, src istanbul.Validator) error { 115 logger := c.logger.NewWith("from", src, "state", c.state) 116 117 // Add the PREPARE message to current round state 118 if err := c.current.Prepares.Add(msg); err != nil { 119 logger.Error("Failed to add PREPARE message to round state", "msg", msg, "err", err) 120 return err 121 } 122 123 return nil 124 }