github.com/ethereum/go-ethereum@v1.16.1/rpc/json.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  	"bytes"
    21  	"context"
    22  	"encoding/json"
    23  	"errors"
    24  	"fmt"
    25  	"io"
    26  	"reflect"
    27  	"strings"
    28  	"sync"
    29  	"time"
    30  )
    31  
    32  const (
    33  	vsn                      = "2.0"
    34  	serviceMethodSeparator   = "_"
    35  	subscribeMethodSuffix    = "_subscribe"
    36  	unsubscribeMethodSuffix  = "_unsubscribe"
    37  	notificationMethodSuffix = "_subscription"
    38  	maxMethodNameLength      = 2048
    39  
    40  	defaultWriteTimeout = 10 * time.Second // used if context has no deadline
    41  )
    42  
    43  var null = json.RawMessage("null")
    44  
    45  type subscriptionResult struct {
    46  	ID     string          `json:"subscription"`
    47  	Result json.RawMessage `json:"result,omitempty"`
    48  }
    49  
    50  type subscriptionResultEnc struct {
    51  	ID     string `json:"subscription"`
    52  	Result any    `json:"result"`
    53  }
    54  
    55  type jsonrpcSubscriptionNotification struct {
    56  	Version string                `json:"jsonrpc"`
    57  	Method  string                `json:"method"`
    58  	Params  subscriptionResultEnc `json:"params"`
    59  }
    60  
    61  // A value of this type can a JSON-RPC request, notification, successful response or
    62  // error response. Which one it is depends on the fields.
    63  type jsonrpcMessage struct {
    64  	Version string          `json:"jsonrpc,omitempty"`
    65  	ID      json.RawMessage `json:"id,omitempty"`
    66  	Method  string          `json:"method,omitempty"`
    67  	Params  json.RawMessage `json:"params,omitempty"`
    68  	Error   *jsonError      `json:"error,omitempty"`
    69  	Result  json.RawMessage `json:"result,omitempty"`
    70  }
    71  
    72  func (msg *jsonrpcMessage) isNotification() bool {
    73  	return msg.hasValidVersion() && msg.ID == nil && msg.Method != ""
    74  }
    75  
    76  func (msg *jsonrpcMessage) isCall() bool {
    77  	return msg.hasValidVersion() && msg.hasValidID() && msg.Method != ""
    78  }
    79  
    80  func (msg *jsonrpcMessage) isResponse() bool {
    81  	return msg.hasValidVersion() && msg.hasValidID() && msg.Method == "" && msg.Params == nil && (msg.Result != nil || msg.Error != nil)
    82  }
    83  
    84  func (msg *jsonrpcMessage) hasValidID() bool {
    85  	return len(msg.ID) > 0 && msg.ID[0] != '{' && msg.ID[0] != '['
    86  }
    87  
    88  func (msg *jsonrpcMessage) hasValidVersion() bool {
    89  	return msg.Version == vsn
    90  }
    91  
    92  func (msg *jsonrpcMessage) isSubscribe() bool {
    93  	return strings.HasSuffix(msg.Method, subscribeMethodSuffix)
    94  }
    95  
    96  func (msg *jsonrpcMessage) isUnsubscribe() bool {
    97  	return strings.HasSuffix(msg.Method, unsubscribeMethodSuffix)
    98  }
    99  
   100  func (msg *jsonrpcMessage) namespace() string {
   101  	before, _, _ := strings.Cut(msg.Method, serviceMethodSeparator)
   102  	return before
   103  }
   104  
   105  func (msg *jsonrpcMessage) String() string {
   106  	b, _ := json.Marshal(msg)
   107  	return string(b)
   108  }
   109  
   110  func (msg *jsonrpcMessage) errorResponse(err error) *jsonrpcMessage {
   111  	resp := errorMessage(err)
   112  	resp.ID = msg.ID
   113  	return resp
   114  }
   115  
   116  func (msg *jsonrpcMessage) response(result interface{}) *jsonrpcMessage {
   117  	enc, err := json.Marshal(result)
   118  	if err != nil {
   119  		return msg.errorResponse(&internalServerError{errcodeMarshalError, err.Error()})
   120  	}
   121  	return &jsonrpcMessage{Version: vsn, ID: msg.ID, Result: enc}
   122  }
   123  
   124  func errorMessage(err error) *jsonrpcMessage {
   125  	msg := &jsonrpcMessage{Version: vsn, ID: null, Error: &jsonError{
   126  		Code:    errcodeDefault,
   127  		Message: err.Error(),
   128  	}}
   129  	ec, ok := err.(Error)
   130  	if ok {
   131  		msg.Error.Code = ec.ErrorCode()
   132  	}
   133  	de, ok := err.(DataError)
   134  	if ok {
   135  		msg.Error.Data = de.ErrorData()
   136  	}
   137  	return msg
   138  }
   139  
   140  type jsonError struct {
   141  	Code    int         `json:"code"`
   142  	Message string      `json:"message"`
   143  	Data    interface{} `json:"data,omitempty"`
   144  }
   145  
   146  func (err *jsonError) Error() string {
   147  	if err.Message == "" {
   148  		return fmt.Sprintf("json-rpc error %d", err.Code)
   149  	}
   150  	return err.Message
   151  }
   152  
   153  func (err *jsonError) ErrorCode() int {
   154  	return err.Code
   155  }
   156  
   157  func (err *jsonError) ErrorData() interface{} {
   158  	return err.Data
   159  }
   160  
   161  // Conn is a subset of the methods of net.Conn which are sufficient for ServerCodec.
   162  type Conn interface {
   163  	io.ReadWriteCloser
   164  	SetWriteDeadline(time.Time) error
   165  }
   166  
   167  type deadlineCloser interface {
   168  	io.Closer
   169  	SetWriteDeadline(time.Time) error
   170  }
   171  
   172  // ConnRemoteAddr wraps the RemoteAddr operation, which returns a description
   173  // of the peer address of a connection. If a Conn also implements ConnRemoteAddr, this
   174  // description is used in log messages.
   175  type ConnRemoteAddr interface {
   176  	RemoteAddr() string
   177  }
   178  
   179  // jsonCodec reads and writes JSON-RPC messages to the underlying connection. It also has
   180  // support for parsing arguments and serializing (result) objects.
   181  type jsonCodec struct {
   182  	remote  string
   183  	closer  sync.Once        // close closed channel once
   184  	closeCh chan interface{} // closed on Close
   185  	decode  decodeFunc       // decoder to allow multiple transports
   186  	encMu   sync.Mutex       // guards the encoder
   187  	encode  encodeFunc       // encoder to allow multiple transports
   188  	conn    deadlineCloser
   189  }
   190  
   191  type encodeFunc = func(v interface{}, isErrorResponse bool) error
   192  
   193  type decodeFunc = func(v interface{}) error
   194  
   195  // NewFuncCodec creates a codec which uses the given functions to read and write. If conn
   196  // implements ConnRemoteAddr, log messages will use it to include the remote address of
   197  // the connection.
   198  func NewFuncCodec(conn deadlineCloser, encode encodeFunc, decode decodeFunc) ServerCodec {
   199  	codec := &jsonCodec{
   200  		closeCh: make(chan interface{}),
   201  		encode:  encode,
   202  		decode:  decode,
   203  		conn:    conn,
   204  	}
   205  	if ra, ok := conn.(ConnRemoteAddr); ok {
   206  		codec.remote = ra.RemoteAddr()
   207  	}
   208  	return codec
   209  }
   210  
   211  // NewCodec creates a codec on the given connection. If conn implements ConnRemoteAddr, log
   212  // messages will use it to include the remote address of the connection.
   213  func NewCodec(conn Conn) ServerCodec {
   214  	enc := json.NewEncoder(conn)
   215  	dec := json.NewDecoder(conn)
   216  	dec.UseNumber()
   217  
   218  	encode := func(v interface{}, isErrorResponse bool) error {
   219  		return enc.Encode(v)
   220  	}
   221  	return NewFuncCodec(conn, encode, dec.Decode)
   222  }
   223  
   224  func (c *jsonCodec) peerInfo() PeerInfo {
   225  	// This returns "ipc" because all other built-in transports have a separate codec type.
   226  	return PeerInfo{Transport: "ipc", RemoteAddr: c.remote}
   227  }
   228  
   229  func (c *jsonCodec) remoteAddr() string {
   230  	return c.remote
   231  }
   232  
   233  func (c *jsonCodec) readBatch() (messages []*jsonrpcMessage, batch bool, err error) {
   234  	// Decode the next JSON object in the input stream.
   235  	// This verifies basic syntax, etc.
   236  	var rawmsg json.RawMessage
   237  	if err := c.decode(&rawmsg); err != nil {
   238  		return nil, false, err
   239  	}
   240  	messages, batch = parseMessage(rawmsg)
   241  	for i, msg := range messages {
   242  		if msg == nil {
   243  			// Message is JSON 'null'. Replace with zero value so it
   244  			// will be treated like any other invalid message.
   245  			messages[i] = new(jsonrpcMessage)
   246  		}
   247  	}
   248  	return messages, batch, nil
   249  }
   250  
   251  func (c *jsonCodec) writeJSON(ctx context.Context, v interface{}, isErrorResponse bool) error {
   252  	c.encMu.Lock()
   253  	defer c.encMu.Unlock()
   254  
   255  	deadline, ok := ctx.Deadline()
   256  	if !ok {
   257  		deadline = time.Now().Add(defaultWriteTimeout)
   258  	}
   259  	c.conn.SetWriteDeadline(deadline)
   260  	return c.encode(v, isErrorResponse)
   261  }
   262  
   263  func (c *jsonCodec) close() {
   264  	c.closer.Do(func() {
   265  		close(c.closeCh)
   266  		c.conn.Close()
   267  	})
   268  }
   269  
   270  // closed returns a channel which will be closed when Close is called
   271  func (c *jsonCodec) closed() <-chan interface{} {
   272  	return c.closeCh
   273  }
   274  
   275  // parseMessage parses raw bytes as a (batch of) JSON-RPC message(s). There are no error
   276  // checks in this function because the raw message has already been syntax-checked when it
   277  // is called. Any non-JSON-RPC messages in the input return the zero value of
   278  // jsonrpcMessage.
   279  func parseMessage(raw json.RawMessage) ([]*jsonrpcMessage, bool) {
   280  	if !isBatch(raw) {
   281  		msgs := []*jsonrpcMessage{{}}
   282  		json.Unmarshal(raw, &msgs[0])
   283  		return msgs, false
   284  	}
   285  	dec := json.NewDecoder(bytes.NewReader(raw))
   286  	dec.Token() // skip '['
   287  	var msgs []*jsonrpcMessage
   288  	for dec.More() {
   289  		msgs = append(msgs, new(jsonrpcMessage))
   290  		dec.Decode(&msgs[len(msgs)-1])
   291  	}
   292  	return msgs, true
   293  }
   294  
   295  // isBatch returns true when the first non-whitespace characters is '['
   296  func isBatch(raw json.RawMessage) bool {
   297  	for _, c := range raw {
   298  		// skip insignificant whitespace (http://www.ietf.org/rfc/rfc4627.txt)
   299  		if c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d {
   300  			continue
   301  		}
   302  		return c == '['
   303  	}
   304  	return false
   305  }
   306  
   307  // parsePositionalArguments tries to parse the given args to an array of values with the
   308  // given types. It returns the parsed values or an error when the args could not be
   309  // parsed. Missing optional arguments are returned as reflect.Zero values.
   310  func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]reflect.Value, error) {
   311  	dec := json.NewDecoder(bytes.NewReader(rawArgs))
   312  	var args []reflect.Value
   313  	tok, err := dec.Token()
   314  	switch {
   315  	case err == io.EOF || tok == nil && err == nil:
   316  		// "params" is optional and may be empty. Also allow "params":null even though it's
   317  		// not in the spec because our own client used to send it.
   318  	case err != nil:
   319  		return nil, err
   320  	case tok == json.Delim('['):
   321  		// Read argument array.
   322  		if args, err = parseArgumentArray(dec, types); err != nil {
   323  			return nil, err
   324  		}
   325  	default:
   326  		return nil, errors.New("non-array args")
   327  	}
   328  	// Set any missing args to nil.
   329  	for i := len(args); i < len(types); i++ {
   330  		if types[i].Kind() != reflect.Ptr {
   331  			return nil, fmt.Errorf("missing value for required argument %d", i)
   332  		}
   333  		args = append(args, reflect.Zero(types[i]))
   334  	}
   335  	return args, nil
   336  }
   337  
   338  func parseArgumentArray(dec *json.Decoder, types []reflect.Type) ([]reflect.Value, error) {
   339  	args := make([]reflect.Value, 0, len(types))
   340  	for i := 0; dec.More(); i++ {
   341  		if i >= len(types) {
   342  			return args, fmt.Errorf("too many arguments, want at most %d", len(types))
   343  		}
   344  		argval := reflect.New(types[i])
   345  		if err := dec.Decode(argval.Interface()); err != nil {
   346  			return args, fmt.Errorf("invalid argument %d: %v", i, err)
   347  		}
   348  		if argval.IsNil() && types[i].Kind() != reflect.Ptr {
   349  			return args, fmt.Errorf("missing value for required argument %d", i)
   350  		}
   351  		args = append(args, argval.Elem())
   352  	}
   353  	// Read end of args array.
   354  	_, err := dec.Token()
   355  	return args, err
   356  }
   357  
   358  // parseSubscriptionName extracts the subscription name from an encoded argument array.
   359  func parseSubscriptionName(rawArgs json.RawMessage) (string, error) {
   360  	dec := json.NewDecoder(bytes.NewReader(rawArgs))
   361  	if tok, _ := dec.Token(); tok != json.Delim('[') {
   362  		return "", errors.New("non-array args")
   363  	}
   364  	v, _ := dec.Token()
   365  	method, ok := v.(string)
   366  	if !ok {
   367  		return "", errors.New("expected subscription name as first argument")
   368  	}
   369  	return method, nil
   370  }