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