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