github.com/Consensys/quorum@v21.1.0+incompatible/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  	"strings"
    25  
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/common/hexutil"
    28  )
    29  
    30  // API describes the set of methods offered over the RPC interface
    31  type API struct {
    32  	Namespace string      // namespace under which the rpc methods of Service are exposed
    33  	Version   string      // api version for DApp's
    34  	Service   interface{} // receiver instance which holds the methods
    35  	Public    bool        // indication if the methods must be considered safe for public use
    36  }
    37  
    38  // Error wraps RPC errors, which contain an error code in addition to the message.
    39  type Error interface {
    40  	Error() string  // returns the message
    41  	ErrorCode() int // returns the code
    42  }
    43  
    44  // ServerCodec implements reading, parsing and writing RPC messages for the server side of
    45  // a RPC session. Implementations must be go-routine safe since the codec can be called in
    46  // multiple go-routines concurrently.
    47  // Quorum:
    48  //   As ServerCodec is used in both client and server implementation, we extend it with the interfaces
    49  //   securityContextConfigurer & securityContextResolver to hold authorization-related information
    50  //   which is then used by rpc/handler to enforce the security
    51  type ServerCodec interface {
    52  	Read() (msgs []*jsonrpcMessage, isBatch bool, err error)
    53  	Close()
    54  	jsonWriter
    55  	securityContextConfigurer
    56  	securityContextResolver
    57  }
    58  
    59  // jsonWriter can write JSON messages to its underlying connection.
    60  // Implementations must be safe for concurrent use.
    61  type jsonWriter interface {
    62  	Write(context.Context, interface{}) error
    63  	// Closed returns a channel which is closed when the connection is closed.
    64  	Closed() <-chan interface{}
    65  	// RemoteAddr returns the peer address of the connection.
    66  	RemoteAddr() string
    67  }
    68  
    69  type BlockNumber int64
    70  
    71  const (
    72  	PendingBlockNumber  = BlockNumber(-2)
    73  	LatestBlockNumber   = BlockNumber(-1)
    74  	EarliestBlockNumber = BlockNumber(0)
    75  )
    76  
    77  // UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports:
    78  // - "latest", "earliest" or "pending" as string arguments
    79  // - the block number
    80  // Returned errors:
    81  // - an invalid block number error when the given argument isn't a known strings
    82  // - an out of range error when the given block number is either too little or too large
    83  func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
    84  	input := strings.TrimSpace(string(data))
    85  	if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' {
    86  		input = input[1 : len(input)-1]
    87  	}
    88  
    89  	switch input {
    90  	case "earliest":
    91  		*bn = EarliestBlockNumber
    92  		return nil
    93  	case "latest":
    94  		*bn = LatestBlockNumber
    95  		return nil
    96  	case "pending":
    97  		*bn = PendingBlockNumber
    98  		return nil
    99  	}
   100  
   101  	blckNum, err := hexutil.DecodeUint64(input)
   102  	if err != nil {
   103  		return err
   104  	}
   105  	if blckNum > math.MaxInt64 {
   106  		return fmt.Errorf("Blocknumber too high")
   107  	}
   108  
   109  	*bn = BlockNumber(blckNum)
   110  	return nil
   111  }
   112  
   113  func (bn BlockNumber) Int64() int64 {
   114  	return (int64)(bn)
   115  }
   116  
   117  type BlockNumberOrHash struct {
   118  	BlockNumber      *BlockNumber `json:"blockNumber,omitempty"`
   119  	BlockHash        *common.Hash `json:"blockHash,omitempty"`
   120  	RequireCanonical bool         `json:"requireCanonical,omitempty"`
   121  }
   122  
   123  func (bnh *BlockNumberOrHash) UnmarshalJSON(data []byte) error {
   124  	type erased BlockNumberOrHash
   125  	e := erased{}
   126  	err := json.Unmarshal(data, &e)
   127  	if err == nil {
   128  		if e.BlockNumber != nil && e.BlockHash != nil {
   129  			return fmt.Errorf("cannot specify both BlockHash and BlockNumber, choose one or the other")
   130  		}
   131  		bnh.BlockNumber = e.BlockNumber
   132  		bnh.BlockHash = e.BlockHash
   133  		bnh.RequireCanonical = e.RequireCanonical
   134  		return nil
   135  	}
   136  	var input string
   137  	err = json.Unmarshal(data, &input)
   138  	if err != nil {
   139  		return err
   140  	}
   141  	switch input {
   142  	case "earliest":
   143  		bn := EarliestBlockNumber
   144  		bnh.BlockNumber = &bn
   145  		return nil
   146  	case "latest":
   147  		bn := LatestBlockNumber
   148  		bnh.BlockNumber = &bn
   149  		return nil
   150  	case "pending":
   151  		bn := PendingBlockNumber
   152  		bnh.BlockNumber = &bn
   153  		return nil
   154  	default:
   155  		if len(input) == 66 {
   156  			hash := common.Hash{}
   157  			err := hash.UnmarshalText([]byte(input))
   158  			if err != nil {
   159  				return err
   160  			}
   161  			bnh.BlockHash = &hash
   162  			return nil
   163  		} else {
   164  			blckNum, err := hexutil.DecodeUint64(input)
   165  			if err != nil {
   166  				return err
   167  			}
   168  			if blckNum > math.MaxInt64 {
   169  				return fmt.Errorf("blocknumber too high")
   170  			}
   171  			bn := BlockNumber(blckNum)
   172  			bnh.BlockNumber = &bn
   173  			return nil
   174  		}
   175  	}
   176  }
   177  
   178  func (bnh *BlockNumberOrHash) Number() (BlockNumber, bool) {
   179  	if bnh.BlockNumber != nil {
   180  		return *bnh.BlockNumber, true
   181  	}
   182  	return BlockNumber(0), false
   183  }
   184  
   185  func (bnh *BlockNumberOrHash) Hash() (common.Hash, bool) {
   186  	if bnh.BlockHash != nil {
   187  		return *bnh.BlockHash, true
   188  	}
   189  	return common.Hash{}, false
   190  }
   191  
   192  func BlockNumberOrHashWithNumber(blockNr BlockNumber) BlockNumberOrHash {
   193  	return BlockNumberOrHash{
   194  		BlockNumber:      &blockNr,
   195  		BlockHash:        nil,
   196  		RequireCanonical: false,
   197  	}
   198  }
   199  
   200  func BlockNumberOrHashWithHash(hash common.Hash, canonical bool) BlockNumberOrHash {
   201  	return BlockNumberOrHash{
   202  		BlockNumber:      nil,
   203  		BlockHash:        &hash,
   204  		RequireCanonical: canonical,
   205  	}
   206  }