internal/ethapi: support block number or hash on state-related methods (#19491)

This change adds support for EIP-1898.
This commit is contained in:
Ryan Schneider
2019-09-26 01:47:31 -07:00
committed by Felix Lange
parent 62391ddbeb
commit ad03d9801c
10 changed files with 408 additions and 166 deletions

View File

@ -18,10 +18,12 @@ package rpc
import (
"context"
"encoding/json"
"fmt"
"math"
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
@ -105,3 +107,94 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
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
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,
}
}