| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- // Copyright 2015 The go-ethereum Authors
- // This file is part of the go-ethereum library.
- //
- // The go-ethereum library is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Lesser General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // The go-ethereum library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Lesser General Public License for more details.
- //
- // You should have received a copy of the GNU Lesser General Public License
- // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
- package rpc
- import (
- "context"
- "encoding/json"
- "fmt"
- "math"
- "strconv"
- "strings"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/hexutil"
- )
- // API describes the set of methods offered over the RPC interface
- type API struct {
- Namespace string // namespace under which the rpc methods of Service are exposed
- Version string // deprecated - this field is no longer used, but retained for compatibility
- Service interface{} // receiver instance which holds the methods
- Public bool // deprecated - this field is no longer used, but retained for compatibility
- Authenticated bool // whether the api should only be available behind authentication.
- }
- // ServerCodec implements reading, parsing and writing RPC messages for the server side of
- // a RPC session. Implementations must be go-routine safe since the codec can be called in
- // multiple go-routines concurrently.
- type ServerCodec interface {
- peerInfo() PeerInfo
- readBatch() (msgs []*jsonrpcMessage, isBatch bool, err error)
- close()
- jsonWriter
- }
- // jsonWriter can write JSON messages to its underlying connection.
- // Implementations must be safe for concurrent use.
- type jsonWriter interface {
- writeJSON(context.Context, interface{}) error
- // Closed returns a channel which is closed when the connection is closed.
- closed() <-chan interface{}
- // RemoteAddr returns the peer address of the connection.
- remoteAddr() string
- }
- type BlockNumber int64
- const (
- SafeBlockNumber = BlockNumber(-4)
- FinalizedBlockNumber = BlockNumber(-3)
- PendingBlockNumber = BlockNumber(-2)
- LatestBlockNumber = BlockNumber(-1)
- EarliestBlockNumber = BlockNumber(0)
- )
- // UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports:
- // - "latest", "earliest" or "pending" as string arguments
- // - the block number
- // Returned errors:
- // - an invalid block number error when the given argument isn't a known strings
- // - an out of range error when the given block number is either too little or too large
- func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
- input := strings.TrimSpace(string(data))
- if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' {
- input = input[1 : len(input)-1]
- }
- switch input {
- case "earliest":
- *bn = EarliestBlockNumber
- return nil
- case "latest":
- *bn = LatestBlockNumber
- return nil
- case "pending":
- *bn = PendingBlockNumber
- return nil
- case "finalized":
- *bn = FinalizedBlockNumber
- return nil
- case "safe":
- *bn = SafeBlockNumber
- return nil
- }
- blckNum, err := hexutil.DecodeUint64(input)
- if err != nil {
- return err
- }
- if blckNum > math.MaxInt64 {
- return fmt.Errorf("block number larger than int64")
- }
- *bn = BlockNumber(blckNum)
- return nil
- }
- // MarshalText implements encoding.TextMarshaler. It marshals:
- // - "latest", "earliest" or "pending" as strings
- // - other numbers as hex
- func (bn BlockNumber) MarshalText() ([]byte, error) {
- switch bn {
- case EarliestBlockNumber:
- return []byte("earliest"), nil
- case LatestBlockNumber:
- return []byte("latest"), nil
- case PendingBlockNumber:
- return []byte("pending"), nil
- case FinalizedBlockNumber:
- return []byte("finalized"), nil
- case SafeBlockNumber:
- return []byte("safe"), nil
- default:
- return hexutil.Uint64(bn).MarshalText()
- }
- }
- func (bn BlockNumber) Int64() int64 {
- return (int64)(bn)
- }
- type BlockNumberOrHash struct {
- BlockNumber *BlockNumber `json:"blockNumber,omitempty"`
- BlockHash *common.Hash `json:"blockHash,omitempty"`
- RequireCanonical bool `json:"requireCanonical,omitempty"`
- }
- func (bnh *BlockNumberOrHash) UnmarshalJSON(data []byte) error {
- type erased BlockNumberOrHash
- e := erased{}
- err := json.Unmarshal(data, &e)
- if err == nil {
- if e.BlockNumber != nil && e.BlockHash != nil {
- return fmt.Errorf("cannot specify both BlockHash and BlockNumber, choose one or the other")
- }
- bnh.BlockNumber = e.BlockNumber
- bnh.BlockHash = e.BlockHash
- bnh.RequireCanonical = e.RequireCanonical
- return nil
- }
- var input string
- err = json.Unmarshal(data, &input)
- if err != nil {
- return err
- }
- switch input {
- case "earliest":
- bn := EarliestBlockNumber
- bnh.BlockNumber = &bn
- return nil
- case "latest":
- bn := LatestBlockNumber
- bnh.BlockNumber = &bn
- return nil
- case "pending":
- bn := PendingBlockNumber
- bnh.BlockNumber = &bn
- return nil
- case "finalized":
- bn := FinalizedBlockNumber
- bnh.BlockNumber = &bn
- return nil
- case "safe":
- bn := SafeBlockNumber
- bnh.BlockNumber = &bn
- return nil
- default:
- if len(input) == 66 {
- hash := common.Hash{}
- err := hash.UnmarshalText([]byte(input))
- if err != nil {
- return err
- }
- bnh.BlockHash = &hash
- return nil
- } else {
- blckNum, err := hexutil.DecodeUint64(input)
- if err != nil {
- return err
- }
- if blckNum > math.MaxInt64 {
- return fmt.Errorf("blocknumber too high")
- }
- bn := BlockNumber(blckNum)
- bnh.BlockNumber = &bn
- return nil
- }
- }
- }
- func (bnh *BlockNumberOrHash) Number() (BlockNumber, bool) {
- if bnh.BlockNumber != nil {
- return *bnh.BlockNumber, true
- }
- return BlockNumber(0), false
- }
- func (bnh *BlockNumberOrHash) String() string {
- if bnh.BlockNumber != nil {
- return strconv.Itoa(int(*bnh.BlockNumber))
- }
- if bnh.BlockHash != nil {
- return bnh.BlockHash.String()
- }
- return "nil"
- }
- func (bnh *BlockNumberOrHash) Hash() (common.Hash, bool) {
- if bnh.BlockHash != nil {
- return *bnh.BlockHash, true
- }
- return common.Hash{}, false
- }
- func BlockNumberOrHashWithNumber(blockNr BlockNumber) BlockNumberOrHash {
- return BlockNumberOrHash{
- BlockNumber: &blockNr,
- BlockHash: nil,
- RequireCanonical: false,
- }
- }
- func BlockNumberOrHashWithHash(hash common.Hash, canonical bool) BlockNumberOrHash {
- return BlockNumberOrHash{
- BlockNumber: nil,
- BlockHash: &hash,
- RequireCanonical: canonical,
- }
- }
- // DecimalOrHex unmarshals a non-negative decimal or hex parameter into a uint64.
- type DecimalOrHex uint64
- // UnmarshalJSON implements json.Unmarshaler.
- func (dh *DecimalOrHex) UnmarshalJSON(data []byte) error {
- input := strings.TrimSpace(string(data))
- if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' {
- input = input[1 : len(input)-1]
- }
- value, err := strconv.ParseUint(input, 10, 64)
- if err != nil {
- value, err = hexutil.DecodeUint64(input)
- }
- if err != nil {
- return err
- }
- *dh = DecimalOrHex(value)
- return nil
- }
|