github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/jsonrpc/types/codec.go (about) 1 package types 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "strings" 8 9 "github.com/0xPolygon/supernets2-node/encoding" 10 "github.com/0xPolygon/supernets2-node/hex" 11 "github.com/jackc/pgx/v4" 12 ) 13 14 const ( 15 // PendingBlockNumber represents the pending block number 16 PendingBlockNumber = BlockNumber(-3) 17 // LatestBlockNumber represents the latest block number 18 LatestBlockNumber = BlockNumber(-2) 19 // EarliestBlockNumber represents the earliest block number 20 EarliestBlockNumber = BlockNumber(-1) 21 // SafeBlockNumber represents the last virtualized block number 22 SafeBlockNumber = BlockNumber(-4) 23 // FinalizedBlockNumber represents the last verified block number 24 FinalizedBlockNumber = BlockNumber(-5) 25 26 // LatestBatchNumber represents the latest batch number 27 LatestBatchNumber = BatchNumber(-2) 28 // EarliestBatchNumber represents the earliest batch number 29 EarliestBatchNumber = BatchNumber(-1) 30 31 // Earliest contains the string to represent the earliest block known. 32 Earliest = "earliest" 33 // Latest contains the string to represent the latest block known. 34 Latest = "latest" 35 // Pending contains the string to represent the pending block known. 36 Pending = "pending" 37 // Safe contains the string to represent the last virtualized block known. 38 Safe = "safe" 39 // Finalized contains the string to represent the last verified block known. 40 Finalized = "finalized" 41 42 // EIP-1898: https://eips.ethereum.org/EIPS/eip-1898 // 43 44 // BlockNumberKey is the key for the block number for EIP-1898 45 BlockNumberKey = "blockNumber" 46 // BlockHashKey is the key for the block hash for EIP-1898 47 BlockHashKey = "blockHash" 48 // RequireCanonicalKey is the key for the require canonical for EIP-1898 49 RequireCanonicalKey = "requireCanonical" 50 ) 51 52 // Request is a jsonrpc request 53 type Request struct { 54 JSONRPC string `json:"jsonrpc"` 55 ID interface{} `json:"id"` 56 Method string `json:"method"` 57 Params json.RawMessage `json:"params,omitempty"` 58 } 59 60 // Response is a jsonrpc success response 61 type Response struct { 62 JSONRPC string 63 ID interface{} 64 Result json.RawMessage 65 Error *ErrorObject 66 } 67 68 // ErrorObject is a jsonrpc error 69 type ErrorObject struct { 70 Code int `json:"code"` 71 Message string `json:"message"` 72 Data *ArgBytes `json:"data,omitempty"` 73 } 74 75 // NewResponse returns Success/Error response object 76 func NewResponse(req Request, reply []byte, err Error) Response { 77 var result json.RawMessage 78 if reply != nil { 79 result = reply 80 } 81 82 var errorObj *ErrorObject 83 if err != nil { 84 errorObj = &ErrorObject{ 85 Code: err.ErrorCode(), 86 Message: err.Error(), 87 } 88 if err.ErrorData() != nil { 89 errorObj.Data = ArgBytesPtr(*err.ErrorData()) 90 } 91 } 92 93 return Response{ 94 JSONRPC: req.JSONRPC, 95 ID: req.ID, 96 Result: result, 97 Error: errorObj, 98 } 99 } 100 101 // MarshalJSON customizes the JSON representation of the response. 102 func (r Response) MarshalJSON() ([]byte, error) { 103 if r.Error != nil { 104 return json.Marshal(struct { 105 JSONRPC string `json:"jsonrpc"` 106 ID interface{} `json:"id"` 107 Error *ErrorObject `json:"error"` 108 }{ 109 JSONRPC: r.JSONRPC, 110 ID: r.ID, 111 Error: r.Error, 112 }) 113 } 114 115 return json.Marshal(struct { 116 JSONRPC string `json:"jsonrpc"` 117 ID interface{} `json:"id"` 118 Result json.RawMessage `json:"result"` 119 }{ 120 JSONRPC: r.JSONRPC, 121 ID: r.ID, 122 Result: r.Result, 123 }) 124 } 125 126 // Bytes return the serialized response 127 func (s Response) Bytes() ([]byte, error) { 128 return json.Marshal(s) 129 } 130 131 // SubscriptionResponse used to push response for filters 132 // that have an active web socket connection 133 type SubscriptionResponse struct { 134 JSONRPC string `json:"jsonrpc"` 135 Method string `json:"method"` 136 Params SubscriptionResponseParams `json:"params"` 137 } 138 139 // SubscriptionResponseParams parameters for subscription responses 140 type SubscriptionResponseParams struct { 141 Subscription string `json:"subscription"` 142 Result json.RawMessage `json:"result"` 143 } 144 145 // Bytes return the serialized response 146 func (s SubscriptionResponse) Bytes() ([]byte, error) { 147 return json.Marshal(s) 148 } 149 150 // BlockNumber is the number of a ethereum block 151 type BlockNumber int64 152 153 // UnmarshalJSON automatically decodes the user input for the block number, when a JSON RPC method is called 154 func (b *BlockNumber) UnmarshalJSON(buffer []byte) error { 155 num, err := StringToBlockNumber(string(buffer)) 156 if err != nil { 157 return err 158 } 159 *b = num 160 return nil 161 } 162 163 // GetNumericBlockNumber returns a numeric block number based on the BlockNumber instance 164 func (b *BlockNumber) GetNumericBlockNumber(ctx context.Context, s StateInterface, dbTx pgx.Tx) (uint64, Error) { 165 bValue := LatestBlockNumber 166 if b != nil { 167 bValue = *b 168 } 169 170 switch bValue { 171 case LatestBlockNumber, PendingBlockNumber: 172 lastBlockNumber, err := s.GetLastL2BlockNumber(ctx, dbTx) 173 if err != nil { 174 return 0, NewRPCError(DefaultErrorCode, "failed to get the last block number from state") 175 } 176 177 return lastBlockNumber, nil 178 179 case EarliestBlockNumber: 180 return 0, nil 181 182 case SafeBlockNumber: 183 lastBlockNumber, err := s.GetLastVirtualizedL2BlockNumber(ctx, dbTx) 184 if err != nil { 185 return 0, NewRPCError(DefaultErrorCode, "failed to get the last virtualized block number from state") 186 } 187 188 return lastBlockNumber, nil 189 190 case FinalizedBlockNumber: 191 lastBlockNumber, err := s.GetLastConsolidatedL2BlockNumber(ctx, dbTx) 192 if err != nil { 193 return 0, NewRPCError(DefaultErrorCode, "failed to get the last verified block number from state") 194 } 195 196 return lastBlockNumber, nil 197 198 default: 199 if bValue < 0 { 200 return 0, NewRPCError(InvalidParamsErrorCode, "invalid block number: %v", bValue) 201 } 202 return uint64(bValue), nil 203 } 204 } 205 206 // StringOrHex returns the block number as a string or hex 207 // n == -3 = pending 208 // n == -2 = latest 209 // n == -1 = earliest 210 // n >= 0 = hex(n) 211 func (b *BlockNumber) StringOrHex() string { 212 switch *b { 213 case EarliestBlockNumber: 214 return Earliest 215 case PendingBlockNumber: 216 return Pending 217 case LatestBlockNumber: 218 return Latest 219 case SafeBlockNumber: 220 return Safe 221 case FinalizedBlockNumber: 222 return Finalized 223 default: 224 return hex.EncodeUint64(uint64(*b)) 225 } 226 } 227 228 // StringToBlockNumber converts a string like "latest" or "0x1" to a BlockNumber instance 229 func StringToBlockNumber(str string) (BlockNumber, error) { 230 str = strings.Trim(str, "\"") 231 switch str { 232 case Earliest: 233 return EarliestBlockNumber, nil 234 case Pending: 235 return PendingBlockNumber, nil 236 case Latest, "": 237 return LatestBlockNumber, nil 238 case Safe: 239 return SafeBlockNumber, nil 240 case Finalized: 241 return FinalizedBlockNumber, nil 242 } 243 244 n, err := encoding.DecodeUint64orHex(&str) 245 if err != nil { 246 return 0, err 247 } 248 return BlockNumber(n), nil 249 } 250 251 // BlockNumberOrHash allows a string value to be parsed 252 // into a block number or a hash, it's used by methods 253 // like eth_call that allows the block to be specified 254 // either by the block number or the block hash 255 type BlockNumberOrHash struct { 256 number *BlockNumber 257 hash *ArgHash 258 requireCanonical bool 259 } 260 261 // IsHash checks if the hash has value 262 func (b *BlockNumberOrHash) IsHash() bool { 263 return b.hash != nil 264 } 265 266 // IsNumber checks if the number has value 267 func (b *BlockNumberOrHash) IsNumber() bool { 268 return b.number != nil 269 } 270 271 // SetHash sets the hash and nullify the number 272 func (b *BlockNumberOrHash) SetHash(hash ArgHash, requireCanonical bool) { 273 t := hash 274 b.number = nil 275 b.hash = &t 276 b.requireCanonical = requireCanonical 277 } 278 279 // SetNumber sets the number and nullify the hash 280 func (b *BlockNumberOrHash) SetNumber(number BlockNumber) { 281 t := number 282 b.number = &t 283 b.hash = nil 284 b.requireCanonical = false 285 } 286 287 // Hash returns the hash 288 func (b *BlockNumberOrHash) Hash() *ArgHash { 289 return b.hash 290 } 291 292 // Number returns the number 293 func (b *BlockNumberOrHash) Number() *BlockNumber { 294 return b.number 295 } 296 297 // UnmarshalJSON automatically decodes the user input for the block number, when a JSON RPC method is called 298 func (b *BlockNumberOrHash) UnmarshalJSON(buffer []byte) error { 299 var number BlockNumber 300 err := json.Unmarshal(buffer, &number) 301 if err == nil { 302 b.SetNumber(number) 303 return nil 304 } 305 306 var hash ArgHash 307 err = json.Unmarshal(buffer, &hash) 308 if err == nil { 309 b.SetHash(hash, false) 310 return nil 311 } 312 313 var m map[string]interface{} 314 err = json.Unmarshal(buffer, &m) 315 if err == nil { 316 if v, ok := m[BlockNumberKey]; ok { 317 input, _ := json.Marshal(v.(string)) 318 err := json.Unmarshal(input, &number) 319 if err == nil { 320 b.SetNumber(number) 321 return nil 322 } 323 } else if v, ok := m[BlockHashKey]; ok { 324 input, _ := json.Marshal(v.(string)) 325 err := json.Unmarshal(input, &hash) 326 if err == nil { 327 requireCanonical, ok := m[RequireCanonicalKey] 328 if ok { 329 switch v := requireCanonical.(type) { 330 case bool: 331 b.SetHash(hash, v) 332 default: 333 return fmt.Errorf("invalid requiredCanonical") 334 } 335 } else { 336 b.SetHash(hash, false) 337 } 338 return nil 339 } 340 } else { 341 return fmt.Errorf("invalid block or hash") 342 } 343 } 344 345 return err 346 } 347 348 // Index of a item 349 type Index int64 350 351 // UnmarshalJSON automatically decodes the user input for the block number, when a JSON RPC method is called 352 func (i *Index) UnmarshalJSON(buffer []byte) error { 353 str := strings.Trim(string(buffer), "\"") 354 n, err := encoding.DecodeUint64orHex(&str) 355 if err != nil { 356 return err 357 } 358 *i = Index(n) 359 return nil 360 } 361 362 // BatchNumber is the number of a ethereum block 363 type BatchNumber int64 364 365 // UnmarshalJSON automatically decodes the user input for the block number, when a JSON RPC method is called 366 func (b *BatchNumber) UnmarshalJSON(buffer []byte) error { 367 num, err := stringToBatchNumber(string(buffer)) 368 if err != nil { 369 return err 370 } 371 *b = num 372 return nil 373 } 374 375 // GetNumericBatchNumber returns a numeric batch number based on the BatchNumber instance 376 func (b *BatchNumber) GetNumericBatchNumber(ctx context.Context, s StateInterface, dbTx pgx.Tx) (uint64, Error) { 377 bValue := LatestBatchNumber 378 if b != nil { 379 bValue = *b 380 } 381 382 switch bValue { 383 case LatestBatchNumber: 384 lastBatchNumber, err := s.GetLastBatchNumber(ctx, dbTx) 385 if err != nil { 386 return 0, NewRPCError(DefaultErrorCode, "failed to get the last batch number from state") 387 } 388 389 return lastBatchNumber, nil 390 391 case EarliestBatchNumber: 392 return 0, nil 393 394 default: 395 if bValue < 0 { 396 return 0, NewRPCError(InvalidParamsErrorCode, "invalid batch number: %v", bValue) 397 } 398 return uint64(bValue), nil 399 } 400 } 401 402 func stringToBatchNumber(str string) (BatchNumber, error) { 403 str = strings.Trim(str, "\"") 404 switch str { 405 case Earliest: 406 return EarliestBatchNumber, nil 407 case Latest, "": 408 return LatestBatchNumber, nil 409 } 410 411 n, err := encoding.DecodeUint64orHex(&str) 412 if err != nil { 413 return 0, err 414 } 415 return BatchNumber(n), nil 416 }