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 }