github.com/shrimpyuk/bor@v0.2.15-0.20220224151350-fb4ec6020bae/internal/cli/server/service.go (about) 1 package server 2 3 import ( 4 "context" 5 "fmt" 6 "math/big" 7 "reflect" 8 "strings" 9 10 "github.com/ethereum/go-ethereum/core" 11 "github.com/ethereum/go-ethereum/core/types" 12 "github.com/ethereum/go-ethereum/internal/cli/server/pprof" 13 "github.com/ethereum/go-ethereum/internal/cli/server/proto" 14 "github.com/ethereum/go-ethereum/p2p" 15 "github.com/ethereum/go-ethereum/p2p/enode" 16 gproto "github.com/golang/protobuf/proto" 17 "github.com/golang/protobuf/ptypes/empty" 18 grpc_net_conn "github.com/mitchellh/go-grpc-net-conn" 19 ) 20 21 func (s *Server) Pprof(req *proto.PprofRequest, stream proto.Bor_PprofServer) error { 22 var payload []byte 23 var headers map[string]string 24 var err error 25 26 ctx := context.Background() 27 switch req.Type { 28 case proto.PprofRequest_CPU: 29 payload, headers, err = pprof.CPUProfile(ctx, int(req.Seconds)) 30 case proto.PprofRequest_TRACE: 31 payload, headers, err = pprof.Trace(ctx, int(req.Seconds)) 32 case proto.PprofRequest_LOOKUP: 33 payload, headers, err = pprof.Profile(req.Profile, 0, 0) 34 } 35 if err != nil { 36 return err 37 } 38 39 // open the stream and send the headers 40 err = stream.Send(&proto.PprofResponse{ 41 Event: &proto.PprofResponse_Open_{ 42 Open: &proto.PprofResponse_Open{ 43 Headers: headers, 44 Size: int64(len(payload)), 45 }, 46 }, 47 }) 48 if err != nil { 49 return err 50 } 51 52 // Wrap our conn around the response. 53 conn := &grpc_net_conn.Conn{ 54 Stream: stream, 55 Request: &proto.PprofResponse_Input{}, 56 Encode: grpc_net_conn.SimpleEncoder(func(msg gproto.Message) *[]byte { 57 return &msg.(*proto.PprofResponse_Input).Data 58 }), 59 } 60 if _, err := conn.Write(payload); err != nil { 61 return err 62 } 63 64 // send the eof 65 err = stream.Send(&proto.PprofResponse{ 66 Event: &proto.PprofResponse_Eof{}, 67 }) 68 if err != nil { 69 return err 70 } 71 return nil 72 } 73 74 func (s *Server) PeersAdd(ctx context.Context, req *proto.PeersAddRequest) (*proto.PeersAddResponse, error) { 75 node, err := enode.Parse(enode.ValidSchemes, req.Enode) 76 if err != nil { 77 return nil, fmt.Errorf("invalid enode: %v", err) 78 } 79 srv := s.node.Server() 80 if req.Trusted { 81 srv.AddTrustedPeer(node) 82 } else { 83 srv.AddPeer(node) 84 } 85 return &proto.PeersAddResponse{}, nil 86 } 87 88 func (s *Server) PeersRemove(ctx context.Context, req *proto.PeersRemoveRequest) (*proto.PeersRemoveResponse, error) { 89 node, err := enode.Parse(enode.ValidSchemes, req.Enode) 90 if err != nil { 91 return nil, fmt.Errorf("invalid enode: %v", err) 92 } 93 srv := s.node.Server() 94 if req.Trusted { 95 srv.RemoveTrustedPeer(node) 96 } else { 97 srv.RemovePeer(node) 98 } 99 return &proto.PeersRemoveResponse{}, nil 100 } 101 102 func (s *Server) PeersList(ctx context.Context, req *proto.PeersListRequest) (*proto.PeersListResponse, error) { 103 resp := &proto.PeersListResponse{} 104 105 peers := s.node.Server().PeersInfo() 106 for _, p := range peers { 107 resp.Peers = append(resp.Peers, peerInfoToPeer(p)) 108 } 109 return resp, nil 110 } 111 112 func (s *Server) PeersStatus(ctx context.Context, req *proto.PeersStatusRequest) (*proto.PeersStatusResponse, error) { 113 var peerInfo *p2p.PeerInfo 114 for _, p := range s.node.Server().PeersInfo() { 115 if strings.HasPrefix(p.ID, req.Enode) { 116 if peerInfo != nil { 117 return nil, fmt.Errorf("more than one peer with the same prefix") 118 } 119 peerInfo = p 120 } 121 } 122 resp := &proto.PeersStatusResponse{} 123 if peerInfo != nil { 124 resp.Peer = peerInfoToPeer(peerInfo) 125 } 126 return resp, nil 127 } 128 129 func peerInfoToPeer(info *p2p.PeerInfo) *proto.Peer { 130 return &proto.Peer{ 131 Id: info.ID, 132 Enode: info.Enode, 133 Enr: info.ENR, 134 Caps: info.Caps, 135 Name: info.Name, 136 Trusted: info.Network.Trusted, 137 Static: info.Network.Static, 138 } 139 } 140 141 func (s *Server) ChainSetHead(ctx context.Context, req *proto.ChainSetHeadRequest) (*proto.ChainSetHeadResponse, error) { 142 s.backend.APIBackend.SetHead(req.Number) 143 return &proto.ChainSetHeadResponse{}, nil 144 } 145 146 func (s *Server) Status(ctx context.Context, _ *empty.Empty) (*proto.StatusResponse, error) { 147 apiBackend := s.backend.APIBackend 148 syncProgress := apiBackend.SyncProgress() 149 150 resp := &proto.StatusResponse{ 151 CurrentHeader: headerToProtoHeader(apiBackend.CurrentHeader()), 152 CurrentBlock: headerToProtoHeader(apiBackend.CurrentBlock().Header()), 153 NumPeers: int64(len(s.node.Server().PeersInfo())), 154 SyncMode: s.config.SyncMode, 155 Syncing: &proto.StatusResponse_Syncing{ 156 StartingBlock: int64(syncProgress.StartingBlock), 157 HighestBlock: int64(syncProgress.HighestBlock), 158 CurrentBlock: int64(syncProgress.CurrentBlock), 159 }, 160 Forks: gatherForks(s.config.chain.Genesis.Config, s.config.chain.Genesis.Config.Bor), 161 } 162 return resp, nil 163 } 164 165 func headerToProtoHeader(h *types.Header) *proto.Header { 166 return &proto.Header{ 167 Hash: h.Hash().String(), 168 Number: h.Number.Uint64(), 169 } 170 } 171 172 var bigIntT = reflect.TypeOf(new(big.Int)).Kind() 173 174 // gatherForks gathers all the fork numbers via reflection 175 func gatherForks(configList ...interface{}) []*proto.StatusResponse_Fork { 176 var forks []*proto.StatusResponse_Fork 177 178 for _, config := range configList { 179 kind := reflect.TypeOf(config) 180 for kind.Kind() == reflect.Ptr { 181 kind = kind.Elem() 182 } 183 184 skip := "DAOForkBlock" 185 186 conf := reflect.ValueOf(config).Elem() 187 for i := 0; i < kind.NumField(); i++ { 188 // Fetch the next field and skip non-fork rules 189 field := kind.Field(i) 190 if strings.Contains(field.Name, skip) { 191 continue 192 } 193 if !strings.HasSuffix(field.Name, "Block") { 194 continue 195 } 196 197 fork := &proto.StatusResponse_Fork{ 198 Name: strings.TrimSuffix(field.Name, "Block"), 199 } 200 201 val := conf.Field(i) 202 switch field.Type.Kind() { 203 case bigIntT: 204 rule := val.Interface().(*big.Int) 205 if rule != nil { 206 fork.Block = rule.Int64() 207 } else { 208 fork.Disabled = true 209 } 210 case reflect.Uint64: 211 fork.Block = int64(val.Uint()) 212 213 default: 214 continue 215 } 216 217 forks = append(forks, fork) 218 } 219 } 220 return forks 221 } 222 223 func convertBlockToBlockStub(blocks []*types.Block) []*proto.BlockStub { 224 225 var blockStubs []*proto.BlockStub 226 227 for _, block := range blocks { 228 blockStub := &proto.BlockStub{ 229 Hash: block.Hash().String(), 230 Number: block.NumberU64(), 231 } 232 blockStubs = append(blockStubs, blockStub) 233 } 234 235 return blockStubs 236 } 237 238 func (s *Server) ChainWatch(req *proto.ChainWatchRequest, reply proto.Bor_ChainWatchServer) error { 239 240 chain2HeadChanSize := 10 241 242 chain2HeadCh := make(chan core.Chain2HeadEvent, chain2HeadChanSize) 243 headSub := s.backend.APIBackend.SubscribeChain2HeadEvent(chain2HeadCh) 244 defer headSub.Unsubscribe() 245 246 for { 247 msg := <-chain2HeadCh 248 249 err := reply.Send(&proto.ChainWatchResponse{Type: msg.Type, 250 Newchain: convertBlockToBlockStub(msg.NewChain), 251 Oldchain: convertBlockToBlockStub(msg.OldChain), 252 }) 253 if err != nil { 254 return err 255 } 256 } 257 }