github.com/klaytn/klaytn@v1.12.1/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 "github.com/klaytn/klaytn/consensus/istanbul" 25 ) 26 27 func (c *core) sendPrepare() { 28 logger := c.logger.NewWith("state", c.state) 29 30 sub := c.current.Subject() 31 prevHash := c.current.Proposal().ParentHash() 32 33 // Do not send message if the owner of the core is not a member of the committee for the `sub.View` 34 if !c.valSet.CheckInSubList(prevHash, sub.View, c.Address()) { 35 return 36 } 37 38 encodedSubject, err := Encode(sub) 39 if err != nil { 40 logger.Error("Failed to encode", "subject", sub) 41 return 42 } 43 44 c.broadcast(&message{ 45 Hash: prevHash, 46 Code: msgPrepare, 47 Msg: encodedSubject, 48 }) 49 } 50 51 func (c *core) handlePrepare(msg *message, src istanbul.Validator) error { 52 // Decode PREPARE message 53 var prepare *istanbul.Subject 54 err := msg.Decode(&prepare) 55 if err != nil { 56 logger.Error("Failed to decode message", "code", msg.Code, "err", err) 57 return errInvalidMessage 58 } 59 60 // logger.Error("call receive prepare","num",prepare.View.Sequence) 61 if err := c.checkMessage(msgPrepare, prepare.View); err != nil { 62 return err 63 } 64 65 // If it is locked, it can only process on the locked block. 66 // Passing verifyPrepare and checkMessage implies it is processing on the locked block since it was verified in the Preprepared state. 67 if err := c.verifyPrepare(prepare, src); err != nil { 68 return err 69 } 70 71 if !c.valSet.CheckInSubList(msg.Hash, prepare.View, src.Address()) { 72 logger.Warn("received an istanbul prepare message from non-committee", 73 "currentSequence", c.current.sequence.Uint64(), "sender", src.Address().String(), "msgView", prepare.View.String()) 74 return errNotFromCommittee 75 } 76 77 c.acceptPrepare(msg, src) 78 79 // Change to Prepared state if we've received enough PREPARE/COMMIT messages or it is locked 80 // and we are in earlier state before Prepared state. 81 // Both of PREPARE and COMMIT messages are counted since the nodes which is hashlocked in 82 // the previous round skip sending PREPARE messages. 83 if c.state.Cmp(StatePrepared) < 0 { 84 if c.current.IsHashLocked() && prepare.Digest == c.current.GetLockedHash() { 85 logger.Warn("received prepare of the hash locked proposal and change state to prepared", "msgType", msgPrepare) 86 c.setState(StatePrepared) 87 c.sendCommit() 88 } else if c.current.GetPrepareOrCommitSize() >= RequiredMessageCount(c.valSet) { 89 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()) 90 c.current.LockHash() 91 c.setState(StatePrepared) 92 c.sendCommit() 93 } 94 } 95 96 return nil 97 } 98 99 // verifyPrepare verifies if the received PREPARE message is equivalent to our subject 100 func (c *core) verifyPrepare(prepare *istanbul.Subject, src istanbul.Validator) error { 101 logger := c.logger.NewWith("from", src, "state", c.state) 102 103 sub := c.current.Subject() 104 if !prepare.Equal(sub) { 105 logger.Warn("Inconsistent subjects between PREPARE and proposal", "expected", sub, "got", prepare) 106 return errInconsistentSubject 107 } 108 109 return nil 110 } 111 112 func (c *core) acceptPrepare(msg *message, src istanbul.Validator) error { 113 logger := c.logger.NewWith("from", src, "state", c.state) 114 115 // Add the PREPARE message to current round state 116 if err := c.current.Prepares.Add(msg); err != nil { 117 logger.Error("Failed to add PREPARE message to round state", "msg", msg, "err", err) 118 return err 119 } 120 121 return nil 122 }