types.go 6.76 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// 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/>.

17
package rpc
18 19

import (
20
	"context"
21
	"encoding/json"
22 23
	"fmt"
	"math"
24
	"strconv"
25 26
	"strings"

27
	"github.com/ethereum/go-ethereum/common"
28
	"github.com/ethereum/go-ethereum/common/hexutil"
29 30 31 32
)

// API describes the set of methods offered over the RPC interface
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 41 42 43
}

// 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 {
44
	peerInfo() PeerInfo
45 46
	readBatch() (msgs []*jsonrpcMessage, isBatch bool, err error)
	close()
47

48 49 50 51 52 53
	jsonWriter
}

// jsonWriter can write JSON messages to its underlying connection.
// Implementations must be safe for concurrent use.
type jsonWriter interface {
54 55 56
	// writeJSON writes a message to the connection.
	writeJSON(ctx context.Context, msg interface{}, isError bool) error

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 64 65
}

type BlockNumber int64

const (
66
	SafeBlockNumber      = BlockNumber(-4)
67
	FinalizedBlockNumber = BlockNumber(-3)
68 69
	LatestBlockNumber    = BlockNumber(-2)
	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 76 77 78 79 80 81 82 83 84
// - 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]
	}

85 86 87 88 89 90 91 92 93
	switch input {
	case "earliest":
		*bn = EarliestBlockNumber
		return nil
	case "latest":
		*bn = LatestBlockNumber
		return nil
	case "pending":
		*bn = PendingBlockNumber
94
		return nil
95 96 97
	case "finalized":
		*bn = FinalizedBlockNumber
		return nil
98 99 100
	case "safe":
		*bn = SafeBlockNumber
		return nil
101 102
	}

103 104 105
	blckNum, err := hexutil.DecodeUint64(input)
	if err != nil {
		return err
106
	}
107
	if blckNum > math.MaxInt64 {
108
		return fmt.Errorf("block number larger than int64")
109
	}
110 111
	*bn = BlockNumber(blckNum)
	return nil
112 113
}

114 115 116 117 118
// Int64 returns the block number as int64.
func (bn BlockNumber) Int64() int64 {
	return (int64)(bn)
}

119
// MarshalText implements encoding.TextMarshaler. It marshals:
120
// - "safe", "finalized", "latest", "earliest" or "pending" as strings
121 122
// - other numbers as hex
func (bn BlockNumber) MarshalText() ([]byte, error) {
123 124 125 126
	return []byte(bn.String()), nil
}

func (bn BlockNumber) String() string {
127 128
	switch bn {
	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 140 141 142
		if bn < 0 {
			return fmt.Sprintf("<invalid %d>", bn)
		}
		return hexutil.Uint64(bn).String()
143 144 145
	}
}

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
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
183 184 185 186
	case "finalized":
		bn := FinalizedBlockNumber
		bnh.BlockNumber = &bn
		return nil
187 188 189 190
	case "safe":
		bn := SafeBlockNumber
		bnh.BlockNumber = &bn
		return nil
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
	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
}

222 223 224 225 226 227 228 229 230 231
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"
}

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
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,
	}
}