github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/rpc/server.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 rpc
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io"
    23  	"sync/atomic"
    24  	"time"
    25  
    26  	mapset "github.com/deckarep/golang-set"
    27  
    28  	"github.com/ethereum/go-ethereum/log"
    29  )
    30  
    31  const MetadataApi = "rpc"
    32  const EngineApi = "engine"
    33  
    34  // CodecOption specifies which type of messages a codec supports.
    35  //
    36  // Deprecated: this option is no longer honored by Server.
    37  type CodecOption int
    38  
    39  const (
    40  	// OptionMethodInvocation is an indication that the codec supports RPC method calls
    41  	OptionMethodInvocation CodecOption = 1 << iota
    42  
    43  	// OptionSubscriptions is an indication that the codec supports RPC notifications
    44  	OptionSubscriptions = 1 << iota // support pub sub
    45  )
    46  
    47  // Server is an RPC server.
    48  type Server struct {
    49  	services serviceRegistry
    50  	idgen    func() ID
    51  	run      int32
    52  	codecs   mapset.Set
    53  
    54  	BatchLimit    uint64
    55  	executionPool *SafePool
    56  }
    57  
    58  // NewServer creates a new server instance with no registered handlers.
    59  func NewServer(executionPoolSize uint64, executionPoolRequesttimeout time.Duration) *Server {
    60  	server := &Server{
    61  		idgen:         randomIDGenerator(),
    62  		codecs:        mapset.NewSet(),
    63  		run:           1,
    64  		executionPool: NewExecutionPool(int(executionPoolSize), executionPoolRequesttimeout),
    65  	}
    66  
    67  	// Register the default service providing meta information about the RPC service such
    68  	// as the services and methods it offers.
    69  	rpcService := &RPCService{server}
    70  	server.RegisterName(MetadataApi, rpcService)
    71  	return server
    72  }
    73  
    74  func (s *Server) SetRPCBatchLimit(batchLimit uint64) {
    75  	s.BatchLimit = batchLimit
    76  }
    77  
    78  func (s *Server) SetExecutionPoolSize(n int) {
    79  	s.executionPool.ChangeSize(n)
    80  }
    81  
    82  func (s *Server) SetExecutionPoolRequestTimeout(n time.Duration) {
    83  	s.executionPool.ChangeTimeout(n)
    84  }
    85  
    86  func (s *Server) GetExecutionPoolRequestTimeout() time.Duration {
    87  	return s.executionPool.Timeout()
    88  }
    89  
    90  func (s *Server) GetExecutionPoolSize() int {
    91  	return s.executionPool.Size()
    92  }
    93  
    94  // RegisterName creates a service for the given receiver type under the given name. When no
    95  // methods on the given receiver match the criteria to be either a RPC method or a
    96  // subscription an error is returned. Otherwise a new service is created and added to the
    97  // service collection this server provides to clients.
    98  func (s *Server) RegisterName(name string, receiver interface{}) error {
    99  	return s.services.registerName(name, receiver)
   100  }
   101  
   102  // ServeCodec reads incoming requests from codec, calls the appropriate callback and writes
   103  // the response back using the given codec. It will block until the codec is closed or the
   104  // server is stopped. In either case the codec is closed.
   105  //
   106  // Note that codec options are no longer supported.
   107  func (s *Server) ServeCodec(codec ServerCodec, options CodecOption) {
   108  	defer codec.close()
   109  
   110  	// Don't serve if server is stopped.
   111  	if atomic.LoadInt32(&s.run) == 0 {
   112  		return
   113  	}
   114  
   115  	// Add the codec to the set so it can be closed by Stop.
   116  	s.codecs.Add(codec)
   117  	defer s.codecs.Remove(codec)
   118  
   119  	c := initClient(codec, s.idgen, &s.services)
   120  	<-codec.closed()
   121  	c.Close()
   122  }
   123  
   124  // serveSingleRequest reads and processes a single RPC request from the given codec. This
   125  // is used to serve HTTP connections. Subscriptions and reverse calls are not allowed in
   126  // this mode.
   127  func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) {
   128  	// Don't serve if server is stopped.
   129  	if atomic.LoadInt32(&s.run) == 0 {
   130  		return
   131  	}
   132  
   133  	h := newHandler(ctx, codec, s.idgen, &s.services, s.executionPool)
   134  
   135  	h.allowSubscribe = false
   136  	defer h.close(io.EOF, nil)
   137  
   138  	reqs, batch, err := codec.readBatch()
   139  	if err != nil {
   140  		if err != io.EOF {
   141  			if err1 := codec.writeJSON(ctx, err); err1 != nil {
   142  				log.Warn("WARNING - error in reading batch", "err", err1)
   143  				return
   144  			}
   145  		}
   146  		return
   147  	}
   148  
   149  	if batch {
   150  		if s.BatchLimit > 0 && len(reqs) > int(s.BatchLimit) {
   151  			if err1 := codec.writeJSON(ctx, errorMessage(fmt.Errorf("batch limit %d exceeded: %d requests given", s.BatchLimit, len(reqs)))); err1 != nil {
   152  				log.Warn("WARNING - requests given exceeds the batch limit", "err", err1)
   153  				log.Debug("batch limit %d exceeded: %d requests given", s.BatchLimit, len(reqs))
   154  			}
   155  		} else {
   156  			//nolint:contextcheck
   157  			h.handleBatch(reqs)
   158  		}
   159  	} else {
   160  		//nolint:contextcheck
   161  		h.handleMsg(reqs[0])
   162  	}
   163  }
   164  
   165  // Stop stops reading new requests, waits for stopPendingRequestTimeout to allow pending
   166  // requests to finish, then closes all codecs which will cancel pending requests and
   167  // subscriptions.
   168  func (s *Server) Stop() {
   169  	if atomic.CompareAndSwapInt32(&s.run, 1, 0) {
   170  		log.Debug("RPC server shutting down")
   171  		s.codecs.Each(func(c interface{}) bool {
   172  			c.(ServerCodec).close()
   173  			return true
   174  		})
   175  	}
   176  }
   177  
   178  // RPCService gives meta information about the server.
   179  // e.g. gives information about the loaded modules.
   180  type RPCService struct {
   181  	server *Server
   182  }
   183  
   184  // Modules returns the list of RPC services with their version number
   185  func (s *RPCService) Modules() map[string]string {
   186  	s.server.services.mu.Lock()
   187  	defer s.server.services.mu.Unlock()
   188  
   189  	modules := make(map[string]string)
   190  	for name := range s.server.services.services {
   191  		modules[name] = "1.0"
   192  	}
   193  	return modules
   194  }
   195  
   196  // PeerInfo contains information about the remote end of the network connection.
   197  //
   198  // This is available within RPC method handlers through the context. Call
   199  // PeerInfoFromContext to get information about the client connection related to
   200  // the current method call.
   201  type PeerInfo struct {
   202  	// Transport is name of the protocol used by the client.
   203  	// This can be "http", "ws" or "ipc".
   204  	Transport string
   205  
   206  	// Address of client. This will usually contain the IP address and port.
   207  	RemoteAddr string
   208  
   209  	// Addditional information for HTTP and WebSocket connections.
   210  	HTTP struct {
   211  		// Protocol version, i.e. "HTTP/1.1". This is not set for WebSocket.
   212  		Version string
   213  		// Header values sent by the client.
   214  		UserAgent string
   215  		Origin    string
   216  		Host      string
   217  	}
   218  }
   219  
   220  type peerInfoContextKey struct{}
   221  
   222  // PeerInfoFromContext returns information about the client's network connection.
   223  // Use this with the context passed to RPC method handler functions.
   224  //
   225  // The zero value is returned if no connection info is present in ctx.
   226  func PeerInfoFromContext(ctx context.Context) PeerInfo {
   227  	info, _ := ctx.Value(peerInfoContextKey{}).(PeerInfo)
   228  	return info
   229  }