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