github.com/dominant-strategies/go-quai@v0.28.2/eth/handler_eth.go (about) 1 // Copyright 2015 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 eth 18 19 import ( 20 "errors" 21 "fmt" 22 "math/big" 23 "sync/atomic" 24 "time" 25 26 "github.com/dominant-strategies/go-quai/common" 27 "github.com/dominant-strategies/go-quai/core" 28 "github.com/dominant-strategies/go-quai/core/types" 29 "github.com/dominant-strategies/go-quai/eth/protocols/eth" 30 "github.com/dominant-strategies/go-quai/log" 31 "github.com/dominant-strategies/go-quai/p2p/enode" 32 ) 33 34 const ( 35 MaxBlockFetchDist = 50 36 ) 37 38 // ethHandler implements the eth.Backend interface to handle the various network 39 // packets that are sent as replies or broadcasts. 40 type ethHandler handler 41 42 func (h *ethHandler) Core() *core.Core { return h.core } 43 func (h *ethHandler) TxPool() eth.TxPool { return h.txpool } 44 45 // RunPeer is invoked when a peer joins on the `eth` protocol. 46 func (h *ethHandler) RunPeer(peer *eth.Peer, hand eth.Handler) error { 47 // Cannot Handshake with a peer before finishing the bad hashes cleanup 48 if h.core.BadHashExistsInChain() { 49 log.Warn("Bad Hashes still exist on chain, cannot handshake with any peer yet") 50 return nil 51 } 52 return (*handler)(h).runEthPeer(peer, hand) 53 } 54 55 // PeerInfo retrieves all known `eth` information about a peer. 56 func (h *ethHandler) PeerInfo(id enode.ID) interface{} { 57 if p := h.peers.peer(id.String()); p != nil { 58 return p.info() 59 } 60 return nil 61 } 62 63 // AcceptTxs retrieves whether transaction processing is enabled on the node 64 // or if inbound transactions should simply be dropped. 65 func (h *ethHandler) AcceptTxs() bool { 66 return atomic.LoadUint32(&h.acceptTxs) == 1 67 } 68 69 // Handle is invoked from a peer's message handler when it receives a new remote 70 // message that the handler couldn't consume and serve itself. 71 func (h *ethHandler) Handle(peer *eth.Peer, packet eth.Packet) error { 72 // Consume any broadcasts and announces, forwarding the rest to the downloader 73 switch packet := packet.(type) { 74 case *eth.BlockHeadersPacket: 75 return h.handleHeaders(peer, *packet) 76 77 case *eth.BlockBodiesPacket: 78 txset, uncleset, etxset, manifestset := packet.Unpack() 79 return h.handleBodies(peer, txset, uncleset, etxset, manifestset) 80 81 case *eth.NewBlockHashesPacket: 82 hashes, numbers := packet.Unpack() 83 return h.handleBlockAnnounces(peer, hashes, numbers) 84 85 case *eth.NewBlockPacket: 86 return h.handleBlockBroadcast(peer, packet.Block, packet.Entropy, packet.Relay) 87 88 case *eth.NewPooledTransactionHashesPacket: 89 return h.txFetcher.Notify(peer.ID(), *packet) 90 91 case *eth.TransactionsPacket: 92 return h.txFetcher.Enqueue(peer.ID(), *packet, false) 93 94 case *eth.PooledTransactionsPacket: 95 return h.txFetcher.Enqueue(peer.ID(), *packet, true) 96 97 default: 98 return fmt.Errorf("unexpected eth packet type: %T", packet) 99 } 100 } 101 102 // handleHeaders is invoked from a peer's message handler when it transmits a batch 103 // of headers for the local node to process. 104 func (h *ethHandler) handleHeaders(peer *eth.Peer, headers []*types.Header) error { 105 p := h.peers.peer(peer.ID()) 106 if p == nil { 107 return errors.New("unregistered during callback") 108 } 109 // If no headers were received, but we're expencting a checkpoint header, consider it that 110 if len(headers) == 0 && p.syncDrop != nil { 111 // Stop the timer either way, decide later to drop or not 112 p.syncDrop.Stop() 113 p.syncDrop = nil 114 } 115 // Filter out any explicitly requested headers, deliver the rest to the downloader 116 filter := len(headers) == 1 117 if filter { 118 // Otherwise if it's a whitelisted block, validate against the set 119 if want, ok := h.whitelist[headers[0].Number().Uint64()]; ok { 120 if hash := headers[0].Hash(); want != hash { 121 peer.Log().Info("Whitelist mismatch, dropping peer", "number", headers[0].Number().Uint64(), "hash", hash, "want", want) 122 return errors.New("whitelist block mismatch") 123 } 124 peer.Log().Debug("Whitelist block verified", "number", headers[0].Number().Uint64(), "hash", want) 125 } 126 // Irrelevant of the fork checks, send the header to the fetcher just in case 127 headers = h.blockFetcher.FilterHeaders(peer.ID(), headers, time.Now()) 128 } 129 if len(headers) > 0 || !filter { 130 err := h.downloader.DeliverHeaders(peer.ID(), headers) 131 if err != nil { 132 log.Debug("Failed to deliver headers", "err", err) 133 } 134 } 135 return nil 136 } 137 138 // handleBodies is invoked from a peer's message handler when it transmits a batch 139 // of block bodies for the local node to process. 140 func (h *ethHandler) handleBodies(peer *eth.Peer, txs [][]*types.Transaction, uncles [][]*types.Header, etxs [][]*types.Transaction, manifest []types.BlockManifest) error { 141 // Filter out any explicitly requested bodies, deliver the rest to the downloader 142 filter := len(txs) > 0 || len(uncles) > 0 || len(etxs) > 0 || len(manifest) > 0 143 if filter { 144 txs, uncles, etxs, manifest = h.blockFetcher.FilterBodies(peer.ID(), txs, uncles, etxs, manifest, time.Now()) 145 } 146 if len(txs) > 0 || len(uncles) > 0 || len(etxs) > 0 || len(manifest) > 0 || !filter { 147 err := h.downloader.DeliverBodies(peer.ID(), txs, uncles, etxs, manifest) 148 if err != nil { 149 log.Debug("Failed to deliver bodies", "err", err) 150 } 151 } 152 return nil 153 } 154 155 // handleBlockAnnounces is invoked from a peer's message handler when it transmits a 156 // batch of block announcements for the local node to process. 157 func (h *ethHandler) handleBlockAnnounces(peer *eth.Peer, hashes []common.Hash, numbers []uint64) error { 158 // Do not handle any broadcast until we finish resetting from the bad state. 159 // This should be a very small time window 160 if h.Core().BadHashExistsInChain() { 161 log.Warn("Bad Hashes still exist on chain, cannot listen to Block Hash announcements yet") 162 return nil 163 } 164 // Schedule all the unknown hashes for retrieval 165 var ( 166 unknownHashes = make([]common.Hash, 0, len(hashes)) 167 unknownNumbers = make([]uint64, 0, len(numbers)) 168 ) 169 for i := 0; i < len(hashes); i++ { 170 if !h.core.HasBlock(hashes[i], numbers[i]) { 171 unknownHashes = append(unknownHashes, hashes[i]) 172 unknownNumbers = append(unknownNumbers, numbers[i]) 173 } 174 } 175 for i := 0; i < len(unknownHashes); i++ { 176 h.blockFetcher.Notify(peer.ID(), unknownHashes[i], unknownNumbers[i], time.Now(), peer.RequestOneHeader, peer.RequestBodies) 177 } 178 return nil 179 } 180 181 // handleBlockBroadcast is invoked from a peer's message handler when it transmits a 182 // block broadcast for the local node to process. 183 func (h *ethHandler) handleBlockBroadcast(peer *eth.Peer, block *types.Block, entropy *big.Int, relay bool) error { 184 // Do not handle any broadcast until we finish resetting from the bad state. 185 // This should be a very small time window 186 if h.Core().BadHashExistsInChain() { 187 log.Warn("Bad Hashes still exist on chain, cannot handle block broadcast yet") 188 return nil 189 } 190 191 syncEntropy, threshold := h.core.SyncTargetEntropy() 192 window := new(big.Int).Mul(threshold, big.NewInt(5)) 193 syncThreshold := new(big.Int).Add(block.ParentEntropy(), window) 194 requestBlock := h.subSyncQueue.Contains(block.Hash()) 195 beyondSyncPoint := syncEntropy.Cmp(syncThreshold) < 0 196 looseSyncEntropyDelta := new(big.Int).Div(syncEntropy, big.NewInt(100)) 197 looseSyncEntropy := new(big.Int).Sub(syncEntropy, looseSyncEntropyDelta) 198 atFray := looseSyncEntropy.Cmp(h.core.CurrentHeader().ParentEntropy()) < 0 199 200 // If block is greater than sync entropy, or its manifest cache, handle it 201 // If block if its in manifest cache, relay is set to true, set relay to false and handle 202 // !atFray checked because when "synced" we want to be able to check entropy against later window 203 log.Debug("Handle Block", "requestBlock", requestBlock, "atFray", atFray, "relay", relay, "beyondSync", beyondSyncPoint) 204 if relay && !atFray { 205 if !beyondSyncPoint { 206 if !requestBlock { 207 // drop peer 208 if common.NodeLocation.Context() != common.PRIME_CTX { 209 log.Info("Peer broadcasting block not in requestQueue or beyond sync target, dropping peer") 210 h.downloader.DropPeer(peer) 211 } 212 return nil 213 } else { 214 relay = false 215 } 216 } 217 } 218 219 h.blockFetcher.ImportBlocks(peer.ID(), block, relay) 220 221 if block != nil && !h.broadcastCache.Contains(block.Hash()) { 222 log.Info("Received Block Broadcast", "Hash", block.Hash(), "Number", block.Header().NumberArray()) 223 h.broadcastCache.Add(block.Hash(), true) 224 } 225 226 _, _, peerEntropy, _ := peer.Head() 227 if entropy != nil && peerEntropy != nil { 228 if peerEntropy.Cmp(entropy) < 0 { 229 peer.SetHead(block.Hash(), block.Number(), entropy, block.ReceivedAt) 230 // Only start the downloader in Prime 231 if common.NodeLocation.Context() == common.PRIME_CTX { 232 h.chainSync.handlePeerEvent(peer) 233 } 234 } 235 } 236 return nil 237 }