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 }