github.com/dim4egster/coreth@v0.10.2/sync/handlers/code_request.go (about) 1 // (c) 2021-2022, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package handlers 5 6 import ( 7 "context" 8 "time" 9 10 "github.com/dim4egster/qmallgo/codec" 11 "github.com/dim4egster/qmallgo/ids" 12 13 "github.com/dim4egster/coreth/core/rawdb" 14 "github.com/dim4egster/coreth/ethdb" 15 "github.com/dim4egster/coreth/params" 16 "github.com/dim4egster/coreth/plugin/evm/message" 17 "github.com/dim4egster/coreth/sync/handlers/stats" 18 "github.com/ethereum/go-ethereum/common" 19 "github.com/ethereum/go-ethereum/log" 20 ) 21 22 // CodeRequestHandler is a peer.RequestHandler for message.CodeRequest 23 // serving requested contract code bytes 24 type CodeRequestHandler struct { 25 codeReader ethdb.KeyValueReader 26 codec codec.Manager 27 stats stats.CodeRequestHandlerStats 28 } 29 30 func NewCodeRequestHandler(codeReader ethdb.KeyValueReader, codec codec.Manager, stats stats.CodeRequestHandlerStats) *CodeRequestHandler { 31 handler := &CodeRequestHandler{ 32 codeReader: codeReader, 33 codec: codec, 34 stats: stats, 35 } 36 return handler 37 } 38 39 // OnCodeRequest handles request to retrieve contract code by its hash in message.CodeRequest 40 // Never returns error 41 // Returns nothing if code hash is not found 42 // Expects returned errors to be treated as FATAL 43 // Assumes ctx is active 44 func (n *CodeRequestHandler) OnCodeRequest(_ context.Context, nodeID ids.NodeID, requestID uint32, codeRequest message.CodeRequest) ([]byte, error) { 45 startTime := time.Now() 46 n.stats.IncCodeRequest() 47 48 // always report code read time metric 49 defer func() { 50 n.stats.UpdateCodeReadTime(time.Since(startTime)) 51 }() 52 53 if len(codeRequest.Hashes) > params.MaxCodeHashesPerRequest { 54 n.stats.IncTooManyHashesRequested() 55 log.Debug("too many hashes requested, dropping request", "nodeID", nodeID, "requestID", requestID, "numHashes", len(codeRequest.Hashes)) 56 return nil, nil 57 } 58 if !isUnique(codeRequest.Hashes) { 59 n.stats.IncDuplicateHashesRequested() 60 log.Debug("duplicate code hashes requested, dropping request", "nodeID", nodeID, "requestID", requestID) 61 return nil, nil 62 } 63 64 codeBytes := make([][]byte, len(codeRequest.Hashes)) 65 totalBytes := 0 66 for i, hash := range codeRequest.Hashes { 67 codeBytes[i] = rawdb.ReadCode(n.codeReader, hash) 68 if len(codeBytes[i]) == 0 { 69 n.stats.IncMissingCodeHash() 70 log.Debug("requested code not found, dropping request", "nodeID", nodeID, "requestID", requestID, "hash", hash) 71 return nil, nil 72 } 73 totalBytes += len(codeBytes[i]) 74 } 75 76 codeResponse := message.CodeResponse{Data: codeBytes} 77 responseBytes, err := n.codec.Marshal(message.Version, codeResponse) 78 if err != nil { 79 log.Warn("could not marshal CodeResponse, dropping request", "nodeID", nodeID, "requestID", requestID, "request", codeRequest, "err", err) 80 return nil, nil 81 } 82 n.stats.UpdateCodeBytesReturned(uint32(totalBytes)) 83 return responseBytes, nil 84 } 85 86 func isUnique(hashes []common.Hash) bool { 87 seen := make(map[common.Hash]struct{}) 88 for _, hash := range hashes { 89 if _, found := seen[hash]; found { 90 return false 91 } 92 seen[hash] = struct{}{} 93 } 94 return true 95 }