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  }