github.com/MetalBlockchain/subnet-evm@v0.4.9/rpc/json.go (about)

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