| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | // 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/>. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 10:58:01 +01:00
										 |  |  | package rpc | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2019-09-26 01:47:31 -07:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"math" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-26 01:47:31 -07:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2017-04-10 13:50:42 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common/hexutil" | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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      // api version for DApp's | 
					
						
							|  |  |  | 	Service   interface{} // receiver instance which holds the methods | 
					
						
							|  |  |  | 	Public    bool        // indication if the methods must be considered safe for public use | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-12 17:47:15 +02:00
										 |  |  | // Error wraps RPC errors, which contain an error code in addition to the message. | 
					
						
							|  |  |  | type Error interface { | 
					
						
							|  |  |  | 	Error() string  // returns the message | 
					
						
							|  |  |  | 	ErrorCode() int // returns the code | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-08 10:09:49 +02:00
										 |  |  | // A DataError contains some data in addition to the error message. | 
					
						
							|  |  |  | type DataError interface { | 
					
						
							|  |  |  | 	Error() string          // returns the message | 
					
						
							|  |  |  | 	ErrorData() interface{} // returns the error data | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | // 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 { | 
					
						
							| 
									
										
										
										
											2019-11-18 09:40:59 +01:00
										 |  |  | 	readBatch() (msgs []*jsonrpcMessage, isBatch bool, err error) | 
					
						
							|  |  |  | 	close() | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | 	jsonWriter | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // jsonWriter can write JSON messages to its underlying connection. | 
					
						
							|  |  |  | // Implementations must be safe for concurrent use. | 
					
						
							|  |  |  | type jsonWriter interface { | 
					
						
							| 
									
										
										
										
											2019-11-18 09:40:59 +01:00
										 |  |  | 	writeJSON(context.Context, interface{}) error | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | 	// Closed returns a channel which is closed when the connection is closed. | 
					
						
							| 
									
										
										
										
											2019-11-18 09:40:59 +01:00
										 |  |  | 	closed() <-chan interface{} | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | 	// RemoteAddr returns the peer address of the connection. | 
					
						
							| 
									
										
										
										
											2019-11-18 09:40:59 +01:00
										 |  |  | 	remoteAddr() string | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type BlockNumber int64 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2017-04-10 13:50:42 +02:00
										 |  |  | 	PendingBlockNumber  = BlockNumber(-2) | 
					
						
							|  |  |  | 	LatestBlockNumber   = BlockNumber(-1) | 
					
						
							|  |  |  | 	EarliestBlockNumber = BlockNumber(0) | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 19:44:35 +02:00
										 |  |  | // UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports: | 
					
						
							| 
									
										
										
										
											2016-01-27 18:01:30 +02:00
										 |  |  | // - "latest", "earliest" or "pending" as string arguments | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | // - 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] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-10 13:50:42 +02:00
										 |  |  | 	switch input { | 
					
						
							|  |  |  | 	case "earliest": | 
					
						
							|  |  |  | 		*bn = EarliestBlockNumber | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	case "latest": | 
					
						
							|  |  |  | 		*bn = LatestBlockNumber | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	case "pending": | 
					
						
							|  |  |  | 		*bn = PendingBlockNumber | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-10 13:50:42 +02:00
										 |  |  | 	blckNum, err := hexutil.DecodeUint64(input) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-10 13:50:42 +02:00
										 |  |  | 	if blckNum > math.MaxInt64 { | 
					
						
							| 
									
										
										
										
											2019-11-20 09:06:21 +01:00
										 |  |  | 		return fmt.Errorf("block number larger than int64") | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-10 13:50:42 +02:00
										 |  |  | 	*bn = BlockNumber(blckNum) | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-27 17:47:46 +02:00
										 |  |  | func (bn BlockNumber) Int64() int64 { | 
					
						
							|  |  |  | 	return (int64)(bn) | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-09-26 01:47:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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 | 
					
						
							|  |  |  | 	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) 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, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |