github.com/cgcardona/r-subnet-evm@v0.1.5/rpc/types.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 "context" 31 "encoding/json" 32 "fmt" 33 "math" 34 "strconv" 35 "strings" 36 37 "github.com/ethereum/go-ethereum/common" 38 "github.com/ethereum/go-ethereum/common/hexutil" 39 ) 40 41 // API describes the set of methods offered over the RPC interface 42 type API struct { 43 Namespace string // namespace under which the rpc methods of Service are exposed 44 Version string // deprecated - this field is no longer used, but retained for compatibility 45 Service interface{} // receiver instance which holds the methods 46 Name string // Name of the API 47 } 48 49 // ServerCodec implements reading, parsing and writing RPC messages for the server side of 50 // a RPC session. Implementations must be go-routine safe since the codec can be called in 51 // multiple go-routines concurrently. 52 type ServerCodec interface { 53 peerInfo() PeerInfo 54 readBatch() (msgs []*jsonrpcMessage, isBatch bool, err error) 55 close() 56 57 jsonWriter 58 } 59 60 // jsonWriter can write JSON messages to its underlying connection. 61 // Implementations must be safe for concurrent use. 62 type jsonWriter interface { 63 writeJSON(context.Context, interface{}) error 64 writeJSONSkipDeadline(context.Context, interface{}, bool) error 65 // Closed returns a channel which is closed when the connection is closed. 66 closed() <-chan interface{} 67 // RemoteAddr returns the peer address of the connection. 68 remoteAddr() string 69 } 70 71 type BlockNumber int64 72 73 const ( 74 AcceptedBlockNumber = BlockNumber(-3) 75 PendingBlockNumber = BlockNumber(-2) 76 LatestBlockNumber = BlockNumber(-1) 77 EarliestBlockNumber = BlockNumber(0) 78 ) 79 80 // UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports: 81 // - "accepted", "finalized", "latest", "earliest" or "pending" as string arguments 82 // - the block number 83 // Returned errors: 84 // - an invalid block number error when the given argument isn't a known strings 85 // - an out of range error when the given block number is either too little or too large 86 func (bn *BlockNumber) UnmarshalJSON(data []byte) error { 87 input := strings.TrimSpace(string(data)) 88 if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' { 89 input = input[1 : len(input)-1] 90 } 91 92 switch input { 93 case "earliest": 94 *bn = EarliestBlockNumber 95 return nil 96 case "latest": 97 *bn = LatestBlockNumber 98 return nil 99 case "pending": 100 *bn = PendingBlockNumber 101 return nil 102 // Include "finalized" and "safe" as an option for compatibility with 103 // FinalizedBlockNumber and SafeBlockNumber from geth. 104 case "accepted", "finalized", "safe": 105 *bn = AcceptedBlockNumber 106 return nil 107 } 108 109 blckNum, err := hexutil.DecodeUint64(input) 110 if err != nil { 111 return err 112 } 113 if blckNum > math.MaxInt64 { 114 return fmt.Errorf("block number larger than int64") 115 } 116 *bn = BlockNumber(blckNum) 117 return nil 118 } 119 120 // MarshalText implements encoding.TextMarshaler. It marshals: 121 // - "accepted", "latest", "earliest" or "pending" as strings 122 // - other numbers as hex 123 func (bn BlockNumber) MarshalText() ([]byte, error) { 124 switch bn { 125 case EarliestBlockNumber: 126 return []byte("earliest"), nil 127 case LatestBlockNumber: 128 return []byte("latest"), nil 129 case PendingBlockNumber: 130 return []byte("pending"), nil 131 case AcceptedBlockNumber: 132 return []byte("accepted"), nil 133 default: 134 return hexutil.Uint64(bn).MarshalText() 135 } 136 } 137 138 func (bn BlockNumber) Int64() int64 { 139 return (int64)(bn) 140 } 141 142 // IsAccepted returns true if this blockNumber should be treated as a request for the last accepted block 143 func (bn BlockNumber) IsAccepted() bool { 144 return bn < EarliestBlockNumber && bn >= AcceptedBlockNumber 145 } 146 147 type BlockNumberOrHash struct { 148 BlockNumber *BlockNumber `json:"blockNumber,omitempty"` 149 BlockHash *common.Hash `json:"blockHash,omitempty"` 150 RequireCanonical bool `json:"requireCanonical,omitempty"` 151 } 152 153 func (bnh *BlockNumberOrHash) UnmarshalJSON(data []byte) error { 154 type erased BlockNumberOrHash 155 e := erased{} 156 err := json.Unmarshal(data, &e) 157 if err == nil { 158 if e.BlockNumber != nil && e.BlockHash != nil { 159 return fmt.Errorf("cannot specify both BlockHash and BlockNumber, choose one or the other") 160 } 161 bnh.BlockNumber = e.BlockNumber 162 bnh.BlockHash = e.BlockHash 163 bnh.RequireCanonical = e.RequireCanonical 164 return nil 165 } 166 var input string 167 err = json.Unmarshal(data, &input) 168 if err != nil { 169 return err 170 } 171 switch input { 172 case "earliest": 173 bn := EarliestBlockNumber 174 bnh.BlockNumber = &bn 175 return nil 176 case "latest": 177 bn := LatestBlockNumber 178 bnh.BlockNumber = &bn 179 return nil 180 case "pending": 181 bn := PendingBlockNumber 182 bnh.BlockNumber = &bn 183 return nil 184 // Include "finalized" and "safe" as an option for compatibility with 185 // FinalizedBlockNumber and SafeBlockNumber from geth. 186 case "accepted", "finalized", "safe": 187 bn := AcceptedBlockNumber 188 bnh.BlockNumber = &bn 189 return nil 190 default: 191 if len(input) == 66 { 192 hash := common.Hash{} 193 err := hash.UnmarshalText([]byte(input)) 194 if err != nil { 195 return err 196 } 197 bnh.BlockHash = &hash 198 return nil 199 } else { 200 blckNum, err := hexutil.DecodeUint64(input) 201 if err != nil { 202 return err 203 } 204 if blckNum > math.MaxInt64 { 205 return fmt.Errorf("blocknumber too high") 206 } 207 bn := BlockNumber(blckNum) 208 bnh.BlockNumber = &bn 209 return nil 210 } 211 } 212 } 213 214 func (bnh *BlockNumberOrHash) Number() (BlockNumber, bool) { 215 if bnh.BlockNumber != nil { 216 return *bnh.BlockNumber, true 217 } 218 return BlockNumber(0), false 219 } 220 221 func (bnh *BlockNumberOrHash) String() string { 222 if bnh.BlockNumber != nil { 223 return strconv.Itoa(int(*bnh.BlockNumber)) 224 } 225 if bnh.BlockHash != nil { 226 return bnh.BlockHash.String() 227 } 228 return "nil" 229 } 230 231 func (bnh *BlockNumberOrHash) Hash() (common.Hash, bool) { 232 if bnh.BlockHash != nil { 233 return *bnh.BlockHash, true 234 } 235 return common.Hash{}, false 236 } 237 238 func BlockNumberOrHashWithNumber(blockNr BlockNumber) BlockNumberOrHash { 239 return BlockNumberOrHash{ 240 BlockNumber: &blockNr, 241 BlockHash: nil, 242 RequireCanonical: false, 243 } 244 } 245 246 func BlockNumberOrHashWithHash(hash common.Hash, canonical bool) BlockNumberOrHash { 247 return BlockNumberOrHash{ 248 BlockNumber: nil, 249 BlockHash: &hash, 250 RequireCanonical: canonical, 251 } 252 } 253 254 // DecimalOrHex unmarshals a non-negative decimal or hex parameter into a uint64. 255 type DecimalOrHex uint64 256 257 // UnmarshalJSON implements json.Unmarshaler. 258 func (dh *DecimalOrHex) UnmarshalJSON(data []byte) error { 259 input := strings.TrimSpace(string(data)) 260 if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' { 261 input = input[1 : len(input)-1] 262 } 263 264 value, err := strconv.ParseUint(input, 10, 64) 265 if err != nil { 266 value, err = hexutil.DecodeUint64(input) 267 } 268 if err != nil { 269 return err 270 } 271 *dh = DecimalOrHex(value) 272 return nil 273 }