github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/consensus/istanbul/backend/handler.go (about) 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 17 package backend 18 19 import ( 20 "bytes" 21 "errors" 22 "io" 23 "math/big" 24 "reflect" 25 26 "github.com/electroneum/electroneum-sc/common" 27 "github.com/electroneum/electroneum-sc/consensus" 28 "github.com/electroneum/electroneum-sc/consensus/istanbul" 29 qbfttypes "github.com/electroneum/electroneum-sc/consensus/istanbul/types" 30 "github.com/electroneum/electroneum-sc/core/types" 31 "github.com/electroneum/electroneum-sc/p2p" 32 lru "github.com/hashicorp/golang-lru" 33 ) 34 35 const ( 36 NewBlockMsg = 0x07 37 istanbulMsg = 0x11 38 ) 39 40 var ( 41 // errDecodeFailed is returned when decode message fails 42 errDecodeFailed = errors.New("fail to decode istanbul message") 43 44 // errPayloadReadFailed is returned when qbft message read fails 45 errPayloadReadFailed = errors.New("unable to read payload from message") 46 ) 47 48 // Protocol implements consensus.Engine.Protocol 49 func (sb *Backend) Protocol() consensus.Protocol { 50 return consensus.IstanbulProtocol 51 } 52 53 func (sb *Backend) decode(msg p2p.Msg) ([]byte, common.Hash, error) { 54 var data []byte = make([]byte, msg.Size) 55 if _, err := msg.Payload.Read(data); err != nil { 56 return nil, common.Hash{}, errPayloadReadFailed 57 } 58 return data, istanbul.RLPHash(data), nil 59 } 60 61 // HandleMsg implements consensus.Handler.HandleMsg 62 func (sb *Backend) HandleMsg(addr common.Address, msg p2p.Msg) (bool, error) { 63 sb.coreMu.Lock() 64 defer sb.coreMu.Unlock() 65 if _, ok := qbfttypes.MessageCodes()[msg.Code]; ok || msg.Code == istanbulMsg { 66 if !sb.coreStarted { 67 return true, istanbul.ErrStoppedEngine 68 } 69 70 data, hash, err := sb.decode(msg) 71 if err != nil { 72 return true, errDecodeFailed 73 } 74 // Mark peer's message 75 ms, ok := sb.recentMessages.Get(addr) 76 var m *lru.ARCCache 77 if ok { 78 m, _ = ms.(*lru.ARCCache) 79 } else { 80 m, _ = lru.NewARC(inmemoryMessages) 81 sb.recentMessages.Add(addr, m) 82 } 83 m.Add(hash, true) 84 85 // Mark self known message 86 if _, ok := sb.knownMessages.Get(hash); ok { 87 return true, nil 88 } 89 sb.knownMessages.Add(hash, true) 90 91 go sb.istanbulEventMux.Post(istanbul.MessageEvent{ 92 Code: msg.Code, 93 Payload: data, 94 }) 95 return true, nil 96 } 97 //https://github.com/ConsenSys/quorum/pull/539 98 //https://github.com/ConsenSys/quorum/issues/389 99 if msg.Code == NewBlockMsg && sb.core != nil && sb.core.IsProposer() { // eth.NewBlockMsg: import cycle 100 // this case is to safeguard the race of similar block which gets propagated from other node while this node is proposing 101 // as p2p.Msg can only be decoded once (get EOF for any subsequence read), we need to make sure the payload is restored after we decode it 102 sb.logger.Debug("IBFT: received NewBlockMsg", "size", msg.Size, "payload.type", reflect.TypeOf(msg.Payload), "sender", addr) 103 if reader, ok := msg.Payload.(*bytes.Reader); ok { 104 payload, err := io.ReadAll(reader) 105 if err != nil { 106 return true, err 107 } 108 reader.Reset(payload) // ready to be decoded 109 defer reader.Reset(payload) // restore so main eth/handler can decode 110 var request struct { // this has to be same as eth/protocol.go#newBlockData as we are reading NewBlockMsg 111 Block *types.Block 112 TD *big.Int 113 } 114 if err := msg.Decode(&request); err != nil { 115 sb.logger.Error("IBFT: unable to decode the NewBlockMsg", "error", err) 116 return false, nil 117 } 118 newRequestedBlock := request.Block 119 if newRequestedBlock.Header().MixDigest == types.IstanbulDigest && sb.core.IsCurrentProposal(newRequestedBlock.Hash()) { 120 sb.logger.Debug("IBFT: block already proposed", "hash", newRequestedBlock.Hash(), "sender", addr) 121 return true, nil 122 } 123 } 124 } 125 return false, nil 126 } 127 128 // SetBroadcaster implements consensus.Handler.SetBroadcaster 129 func (sb *Backend) SetBroadcaster(broadcaster consensus.Broadcaster) { 130 sb.broadcaster = broadcaster 131 } 132 133 func (sb *Backend) NewChainHead() error { 134 sb.coreMu.RLock() 135 defer sb.coreMu.RUnlock() 136 if !sb.coreStarted { 137 return istanbul.ErrStoppedEngine 138 } 139 go sb.istanbulEventMux.Post(istanbul.FinalCommittedEvent{}) 140 return nil 141 }