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