github.com/klaytn/klaytn@v1.10.2/networks/rpc/types.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from rpc/types.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package rpc
    22  
    23  import (
    24  	"context"
    25  	"encoding/json"
    26  	"fmt"
    27  	"math"
    28  	"strings"
    29  
    30  	"github.com/klaytn/klaytn/common"
    31  	"github.com/klaytn/klaytn/common/hexutil"
    32  )
    33  
    34  // API describes the set of methods offered over the RPC interface
    35  type API struct {
    36  	Namespace string      // namespace under which the rpc methods of Service are exposed
    37  	Version   string      // api version for DApp's
    38  	Service   interface{} // receiver instance which holds the methods
    39  	Public    bool        // indication if the methods must be considered safe for public use
    40  }
    41  
    42  // Error wraps RPC errors, which contain an error code in addition to the message.
    43  type Error interface {
    44  	Error() string  // returns the message
    45  	ErrorCode() int // returns the code
    46  }
    47  
    48  // A DataError contains some data in addition to the error message.
    49  type DataError interface {
    50  	Error() string          // returns the message
    51  	ErrorData() interface{} // returns the error data
    52  }
    53  
    54  // ServerCodec implements reading, parsing and writing RPC messages for the server side of
    55  // a RPC session. Implementations must be go-routine safe since the codec can be called in
    56  // multiple go-routines concurrently.
    57  type ServerCodec interface {
    58  	readBatch() (msgs []*jsonrpcMessage, isBatch bool, err error)
    59  	close()
    60  	jsonWriter
    61  }
    62  
    63  // jsonWriter can write JSON messages to its underlying connection.
    64  // Implementations must be safe for concurrent use.
    65  type jsonWriter interface {
    66  	writeJSON(context.Context, interface{}) error
    67  	// Closed returns a channel which is closed when the connection is closed.
    68  	closed() <-chan interface{}
    69  	// RemoteAddr returns the peer address of the connection.
    70  	remoteAddr() string
    71  }
    72  
    73  type BlockNumber int64
    74  
    75  const (
    76  	PendingBlockNumber  = BlockNumber(-2)
    77  	LatestBlockNumber   = BlockNumber(-1)
    78  	EarliestBlockNumber = BlockNumber(0)
    79  )
    80  
    81  // UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports:
    82  // - "latest", "earliest" or "pending" as string arguments
    83  // - the block number
    84  // Returned errors:
    85  // - an invalid block number error when the given argument isn't a known strings
    86  // - an out of range error when the given block number is either too little or too large
    87  func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
    88  	var decimalInput uint64
    89  	err := json.Unmarshal(data, &decimalInput)
    90  	if err == nil {
    91  		*bn = BlockNumber(decimalInput)
    92  		return nil
    93  	}
    94  
    95  	input := strings.TrimSpace(string(data))
    96  	if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' {
    97  		input = input[1 : len(input)-1]
    98  	}
    99  
   100  	switch input {
   101  	case "earliest":
   102  		*bn = EarliestBlockNumber
   103  		return nil
   104  	case "latest":
   105  		*bn = LatestBlockNumber
   106  		return nil
   107  	case "pending":
   108  		*bn = PendingBlockNumber
   109  		return nil
   110  	}
   111  
   112  	blckNum, err := hexutil.DecodeUint64(input)
   113  	if err != nil {
   114  		return err
   115  	}
   116  	if blckNum > math.MaxInt64 {
   117  		return fmt.Errorf("Blocknumber too high")
   118  	}
   119  
   120  	*bn = BlockNumber(blckNum)
   121  	return nil
   122  }
   123  
   124  func (bn BlockNumber) Int64() int64 {
   125  	return (int64)(bn)
   126  }
   127  
   128  func (bn BlockNumber) Uint64() uint64 {
   129  	return (uint64)(bn)
   130  }
   131  
   132  type BlockNumberOrHash struct {
   133  	BlockNumber      *BlockNumber `json:"blockNumber,omitempty"`
   134  	BlockHash        *common.Hash `json:"blockHash,omitempty"`
   135  	RequireCanonical bool         `json:"requireCanonical,omitempty"`
   136  }
   137  
   138  func (bnh *BlockNumberOrHash) UnmarshalJSON(data []byte) error {
   139  	type erased BlockNumberOrHash
   140  	e := erased{}
   141  	err := json.Unmarshal(data, &e)
   142  	if err == nil {
   143  		if e.BlockNumber != nil && e.BlockHash != nil {
   144  			return fmt.Errorf("cannot specify both BlockHash and BlockNumber, choose one or the other")
   145  		}
   146  		bnh.BlockNumber = e.BlockNumber
   147  		bnh.BlockHash = e.BlockHash
   148  		bnh.RequireCanonical = e.RequireCanonical
   149  		return nil
   150  	}
   151  
   152  	var decimalInput uint64
   153  	err = json.Unmarshal(data, &decimalInput)
   154  	if err == nil {
   155  		bn := BlockNumber(decimalInput)
   156  		bnh.BlockNumber = &bn
   157  		return nil
   158  	}
   159  
   160  	var input string
   161  	err = json.Unmarshal(data, &input)
   162  	if err != nil {
   163  		return err
   164  	}
   165  	switch input {
   166  	case "earliest":
   167  		bn := EarliestBlockNumber
   168  		bnh.BlockNumber = &bn
   169  		return nil
   170  	case "latest":
   171  		bn := LatestBlockNumber
   172  		bnh.BlockNumber = &bn
   173  		return nil
   174  	case "pending":
   175  		bn := PendingBlockNumber
   176  		bnh.BlockNumber = &bn
   177  		return nil
   178  	default:
   179  		if len(input) == 66 {
   180  			hash := common.Hash{}
   181  			err := hash.UnmarshalText([]byte(input))
   182  			if err != nil {
   183  				return err
   184  			}
   185  			bnh.BlockHash = &hash
   186  			return nil
   187  		} else {
   188  			blckNum, err := hexutil.DecodeUint64(input)
   189  			if err != nil {
   190  				return err
   191  			}
   192  			if blckNum > math.MaxInt64 {
   193  				return fmt.Errorf("blocknumber too high")
   194  			}
   195  			bn := BlockNumber(blckNum)
   196  			bnh.BlockNumber = &bn
   197  			return nil
   198  		}
   199  	}
   200  }
   201  
   202  func (bnh *BlockNumberOrHash) Number() (BlockNumber, bool) {
   203  	if bnh.BlockNumber != nil {
   204  		return *bnh.BlockNumber, true
   205  	}
   206  	return BlockNumber(0), false
   207  }
   208  
   209  func (bnh *BlockNumberOrHash) Hash() (common.Hash, bool) {
   210  	if bnh.BlockHash != nil {
   211  		return *bnh.BlockHash, true
   212  	}
   213  	return common.Hash{}, false
   214  }
   215  
   216  func (bnh *BlockNumberOrHash) NumberOrHashString() (string, bool) {
   217  	if bnh.BlockNumber != nil {
   218  		return fmt.Sprintf("#%v", bnh.BlockNumber.Int64()), true
   219  	}
   220  	if bnh.BlockHash != nil {
   221  		return bnh.BlockHash.String(), true
   222  	}
   223  	return "", false
   224  }
   225  
   226  func NewBlockNumberOrHashWithNumber(blockNr BlockNumber) BlockNumberOrHash {
   227  	return BlockNumberOrHash{
   228  		BlockNumber:      &blockNr,
   229  		BlockHash:        nil,
   230  		RequireCanonical: false,
   231  	}
   232  }
   233  
   234  func NewBlockNumberOrHashWithHash(hash common.Hash, canonical bool) BlockNumberOrHash {
   235  	return BlockNumberOrHash{
   236  		BlockNumber:      nil,
   237  		BlockHash:        &hash,
   238  		RequireCanonical: canonical,
   239  	}
   240  }