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  }