github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/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  	"fmt"
    23  	"math"
    24  	"strconv"
    25  	"strings"
    26  
    27  	"github.com/electroneum/electroneum-sc/common"
    28  	"github.com/electroneum/electroneum-sc/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      // api version for DApp's
    35  	Service       interface{} // receiver instance which holds the methods
    36  	Public        bool        // indication if the methods must be considered safe for public use
    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  // a 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(context.Context, interface{}) error
    55  	// Closed returns a channel which is closed when the connection is closed.
    56  	closed() <-chan interface{}
    57  	// RemoteAddr returns the peer address of the connection.
    58  	remoteAddr() string
    59  }
    60  
    61  type BlockNumber int64
    62  
    63  const (
    64  	FinalizedBlockNumber = BlockNumber(-3)
    65  	PendingBlockNumber   = BlockNumber(-2)
    66  	LatestBlockNumber    = BlockNumber(-1)
    67  	EarliestBlockNumber  = BlockNumber(0)
    68  )
    69  
    70  // UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports:
    71  // - "latest", "earliest" or "pending" as string arguments
    72  // - the block number
    73  // Returned errors:
    74  // - an invalid block number error when the given argument isn't a known strings
    75  // - an out of range error when the given block number is either too little or too large
    76  func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
    77  	input := strings.TrimSpace(string(data))
    78  	if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' {
    79  		input = input[1 : len(input)-1]
    80  	}
    81  
    82  	switch input {
    83  	case "earliest":
    84  		*bn = EarliestBlockNumber
    85  		return nil
    86  	case "latest":
    87  		*bn = LatestBlockNumber
    88  		return nil
    89  	case "pending":
    90  		*bn = PendingBlockNumber
    91  		return nil
    92  	case "finalized":
    93  		*bn = FinalizedBlockNumber
    94  		return nil
    95  	}
    96  
    97  	blckNum, err := hexutil.DecodeUint64(input)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	if blckNum > math.MaxInt64 {
   102  		return fmt.Errorf("block number larger than int64")
   103  	}
   104  	*bn = BlockNumber(blckNum)
   105  	return nil
   106  }
   107  
   108  // MarshalText implements encoding.TextMarshaler. It marshals:
   109  // - "latest", "earliest" or "pending" as strings
   110  // - other numbers as hex
   111  func (bn BlockNumber) MarshalText() ([]byte, error) {
   112  	switch bn {
   113  	case EarliestBlockNumber:
   114  		return []byte("earliest"), nil
   115  	case LatestBlockNumber:
   116  		return []byte("latest"), nil
   117  	case PendingBlockNumber:
   118  		return []byte("pending"), nil
   119  	case FinalizedBlockNumber:
   120  		return []byte("finalized"), nil
   121  	default:
   122  		return hexutil.Uint64(bn).MarshalText()
   123  	}
   124  }
   125  
   126  func (bn BlockNumber) Int64() int64 {
   127  	return (int64)(bn)
   128  }
   129  
   130  type BlockNumberOrHash struct {
   131  	BlockNumber      *BlockNumber `json:"blockNumber,omitempty"`
   132  	BlockHash        *common.Hash `json:"blockHash,omitempty"`
   133  	RequireCanonical bool         `json:"requireCanonical,omitempty"`
   134  }
   135  
   136  func (bnh *BlockNumberOrHash) UnmarshalJSON(data []byte) error {
   137  	type erased BlockNumberOrHash
   138  	e := erased{}
   139  	err := json.Unmarshal(data, &e)
   140  	if err == nil {
   141  		if e.BlockNumber != nil && e.BlockHash != nil {
   142  			return fmt.Errorf("cannot specify both BlockHash and BlockNumber, choose one or the other")
   143  		}
   144  		bnh.BlockNumber = e.BlockNumber
   145  		bnh.BlockHash = e.BlockHash
   146  		bnh.RequireCanonical = e.RequireCanonical
   147  		return nil
   148  	}
   149  	var input string
   150  	err = json.Unmarshal(data, &input)
   151  	if err != nil {
   152  		return err
   153  	}
   154  	switch input {
   155  	case "earliest":
   156  		bn := EarliestBlockNumber
   157  		bnh.BlockNumber = &bn
   158  		return nil
   159  	case "latest":
   160  		bn := LatestBlockNumber
   161  		bnh.BlockNumber = &bn
   162  		return nil
   163  	case "pending":
   164  		bn := PendingBlockNumber
   165  		bnh.BlockNumber = &bn
   166  		return nil
   167  	case "finalized":
   168  		bn := FinalizedBlockNumber
   169  		bnh.BlockNumber = &bn
   170  		return nil
   171  	default:
   172  		if len(input) == 66 {
   173  			hash := common.Hash{}
   174  			err := hash.UnmarshalText([]byte(input))
   175  			if err != nil {
   176  				return err
   177  			}
   178  			bnh.BlockHash = &hash
   179  			return nil
   180  		} else {
   181  			blckNum, err := hexutil.DecodeUint64(input)
   182  			if err != nil {
   183  				return err
   184  			}
   185  			if blckNum > math.MaxInt64 {
   186  				return fmt.Errorf("blocknumber too high")
   187  			}
   188  			bn := BlockNumber(blckNum)
   189  			bnh.BlockNumber = &bn
   190  			return nil
   191  		}
   192  	}
   193  }
   194  
   195  func (bnh *BlockNumberOrHash) Number() (BlockNumber, bool) {
   196  	if bnh.BlockNumber != nil {
   197  		return *bnh.BlockNumber, true
   198  	}
   199  	return BlockNumber(0), false
   200  }
   201  
   202  func (bnh *BlockNumberOrHash) String() string {
   203  	if bnh.BlockNumber != nil {
   204  		return strconv.Itoa(int(*bnh.BlockNumber))
   205  	}
   206  	if bnh.BlockHash != nil {
   207  		return bnh.BlockHash.String()
   208  	}
   209  	return "nil"
   210  }
   211  
   212  func (bnh *BlockNumberOrHash) Hash() (common.Hash, bool) {
   213  	if bnh.BlockHash != nil {
   214  		return *bnh.BlockHash, true
   215  	}
   216  	return common.Hash{}, false
   217  }
   218  
   219  func BlockNumberOrHashWithNumber(blockNr BlockNumber) BlockNumberOrHash {
   220  	return BlockNumberOrHash{
   221  		BlockNumber:      &blockNr,
   222  		BlockHash:        nil,
   223  		RequireCanonical: false,
   224  	}
   225  }
   226  
   227  func BlockNumberOrHashWithHash(hash common.Hash, canonical bool) BlockNumberOrHash {
   228  	return BlockNumberOrHash{
   229  		BlockNumber:      nil,
   230  		BlockHash:        &hash,
   231  		RequireCanonical: canonical,
   232  	}
   233  }
   234  
   235  // DecimalOrHex unmarshals a non-negative decimal or hex parameter into a uint64.
   236  type DecimalOrHex uint64
   237  
   238  // UnmarshalJSON implements json.Unmarshaler.
   239  func (dh *DecimalOrHex) UnmarshalJSON(data []byte) error {
   240  	input := strings.TrimSpace(string(data))
   241  	if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' {
   242  		input = input[1 : len(input)-1]
   243  	}
   244  
   245  	value, err := strconv.ParseUint(input, 10, 64)
   246  	if err != nil {
   247  		value, err = hexutil.DecodeUint64(input)
   248  	}
   249  	if err != nil {
   250  		return err
   251  	}
   252  	*dh = DecimalOrHex(value)
   253  	return nil
   254  }