Skip to content

Commit

Permalink
Merge PR: eip-1898 (#1024)
Browse files Browse the repository at this point in the history
* eip-1898

* update error message
  • Loading branch information
ilovers authored Sep 16, 2021
1 parent 64d3411 commit 569c89a
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 22 deletions.
29 changes: 29 additions & 0 deletions app/rpc/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package backend
import (
"context"
"fmt"

"github.com/okex/exchain/x/evm/watcher"
"github.com/tendermint/tendermint/libs/log"
"golang.org/x/time/rate"
Expand Down Expand Up @@ -47,6 +48,9 @@ type Backend interface {
GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error)
BloomStatus() (uint64, uint64)
ServiceFilter(ctx context.Context, session *bloombits.MatcherSession)

// Used by eip-1898
ConvertToBlockNumber(rpctypes.BlockNumberOrHash) (rpctypes.BlockNumber, error)
}

var _ Backend = (*EthermintBackend)(nil)
Expand Down Expand Up @@ -448,3 +452,28 @@ func (b *EthermintBackend) IsDisabled(apiName string) bool {
}
return b.disableAPI[apiName]
}

func (b *EthermintBackend) ConvertToBlockNumber(blockNumberOrHash rpctypes.BlockNumberOrHash) (rpctypes.BlockNumber, error) {
if blockNumber, ok := blockNumberOrHash.Number(); ok {
return blockNumber, nil
}
hash, ok := blockNumberOrHash.Hash()
if !ok {
return rpctypes.LatestBlockNumber, nil
}
ethBlock, err := b.wrappedBackend.GetBlockByHash(hash, false)
if err == nil {
return rpctypes.BlockNumber(ethBlock.Number), nil
}

res, _, err := b.clientCtx.Query(fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryHashToHeight, hash.Hex()))
if err != nil {
return rpctypes.LatestBlockNumber, rpctypes.ErrResourceNotFound
}

var out evmtypes.QueryResBlockNumber
if err := b.clientCtx.Codec.UnmarshalJSON(res, &out); err != nil {
return rpctypes.LatestBlockNumber, rpctypes.ErrResourceNotFound
}
return rpctypes.BlockNumber(out.Number), nil
}
61 changes: 44 additions & 17 deletions app/rpc/namespaces/eth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,9 @@ func (api *PublicEthereumAPI) BlockNumber() (hexutil.Uint64, error) {
}

// GetBalance returns the provided account's balance up to the provided block number.
func (api *PublicEthereumAPI) GetBalance(address common.Address, blockNum rpctypes.BlockNumber) (*hexutil.Big, error) {
func (api *PublicEthereumAPI) GetBalance(address common.Address, blockNrOrHash rpctypes.BlockNumberOrHash) (*hexutil.Big, error) {
monitor := monitor.GetMonitor("eth_getBalance", api.logger, api.Metrics).OnBegin()
defer monitor.OnEnd("address", address, "block number", blockNum)
defer monitor.OnEnd("address", address, "block number", blockNrOrHash)
acc, err := api.wrappedBackend.MustGetAccount(address.Bytes())
if err == nil {
balance := acc.GetCoins().AmountOf(sdk.DefaultBondDenom).BigInt()
Expand All @@ -283,6 +283,11 @@ func (api *PublicEthereumAPI) GetBalance(address common.Address, blockNum rpctyp
}
return (*hexutil.Big)(balance), nil
}

blockNum, err := api.backend.ConvertToBlockNumber(blockNrOrHash)
if err != nil {
return nil, err
}
clientCtx := api.clientCtx
if !(blockNum == rpctypes.PendingBlockNumber || blockNum == rpctypes.LatestBlockNumber) {
clientCtx = api.clientCtx.WithHeight(blockNum.Int64())
Expand Down Expand Up @@ -386,9 +391,13 @@ func (api *PublicEthereumAPI) getStorageAt(address common.Address, key []byte, b
}

// GetStorageAt returns the contract storage at the given address, block number, and key.
func (api *PublicEthereumAPI) GetStorageAt(address common.Address, key string, blockNum rpctypes.BlockNumber) (hexutil.Bytes, error) {
func (api *PublicEthereumAPI) GetStorageAt(address common.Address, key string, blockNrOrHash rpctypes.BlockNumberOrHash) (hexutil.Bytes, error) {
monitor := monitor.GetMonitor("eth_getStorageAt", api.logger, api.Metrics).OnBegin()
defer monitor.OnEnd("address", address, "key", key, "block number", blockNum)
defer monitor.OnEnd("address", address, "key", key, "block number", blockNrOrHash)
blockNum, err := api.backend.ConvertToBlockNumber(blockNrOrHash)
if err != nil {
return nil, err
}
return api.getStorageAt(address, common.HexToHash(key).Bytes(), blockNum, false)
}

Expand All @@ -398,9 +407,14 @@ func (api *PublicEthereumAPI) GetStorageAtInternal(address common.Address, key [
}

// GetTransactionCount returns the number of transactions at the given address up to the given block number.
func (api *PublicEthereumAPI) GetTransactionCount(address common.Address, blockNum rpctypes.BlockNumber) (*hexutil.Uint64, error) {
func (api *PublicEthereumAPI) GetTransactionCount(address common.Address, blockNrOrHash rpctypes.BlockNumberOrHash) (*hexutil.Uint64, error) {
monitor := monitor.GetMonitor("eth_getTransactionCount", api.logger, api.Metrics).OnBegin()
defer monitor.OnEnd("address", address, "block number", blockNum)
defer monitor.OnEnd("address", address, "block number", blockNrOrHash)

blockNum, err := api.backend.ConvertToBlockNumber(blockNrOrHash)
if err != nil {
return nil, err
}
clientCtx := api.clientCtx
pending := blockNum == rpctypes.PendingBlockNumber
// pass the given block height to the context if the height is not pending or latest
Expand Down Expand Up @@ -501,9 +515,13 @@ func (api *PublicEthereumAPI) GetUncleCountByBlockNumber(_ rpctypes.BlockNumber)
}

// GetCode returns the contract code at the given address and block number.
func (api *PublicEthereumAPI) GetCode(address common.Address, blockNumber rpctypes.BlockNumber) (hexutil.Bytes, error) {
func (api *PublicEthereumAPI) GetCode(address common.Address, blockNrOrHash rpctypes.BlockNumberOrHash) (hexutil.Bytes, error) {
monitor := monitor.GetMonitor("eth_getCode", api.logger, api.Metrics).OnBegin()
defer monitor.OnEnd("address", address, "block number", blockNumber)
defer monitor.OnEnd("address", address, "block number", blockNrOrHash)
blockNumber, err := api.backend.ConvertToBlockNumber(blockNrOrHash)
if err != nil {
return nil, err
}
height := blockNumber.Int64()
if blockNumber == rpctypes.PendingBlockNumber || blockNumber == rpctypes.LatestBlockNumber {
height, _ = api.backend.LatestBlockNumber()
Expand Down Expand Up @@ -706,14 +724,18 @@ func (api *PublicEthereumAPI) addCallCache(key common.Hash, data []byte) {
}

// Call performs a raw contract call.
func (api *PublicEthereumAPI) Call(args rpctypes.CallArgs, blockNr rpctypes.BlockNumber, _ *map[common.Address]rpctypes.Account) (hexutil.Bytes, error) {
func (api *PublicEthereumAPI) Call(args rpctypes.CallArgs, blockNrOrHash rpctypes.BlockNumberOrHash, _ *map[common.Address]rpctypes.Account) (hexutil.Bytes, error) {
monitor := monitor.GetMonitor("eth_call", api.logger, api.Metrics).OnBegin()
defer monitor.OnEnd("args", args, "block number", blockNr)
defer monitor.OnEnd("args", args, "block number", blockNrOrHash)
key := api.buildKey(args)
cacheData, ok := api.getFromCallCache(key)
if ok {
return cacheData, nil
}
blockNr, err := api.backend.ConvertToBlockNumber(blockNrOrHash)
if err != nil {
return nil, err
}
simRes, err := api.doCall(args, blockNr, big.NewInt(ethermint.DefaultRPCGasLimit), false)
if err != nil {
return []byte{}, TransformDataError(err, "eth_call")
Expand All @@ -736,9 +758,10 @@ func (api *PublicEthereumAPI) MultiCall(args []rpctypes.CallArgs, blockNr rpctyp
monitor := monitor.GetMonitor("eth_multiCall", api.logger, api.Metrics).OnBegin()
defer monitor.OnEnd("args", args, "block number", blockNr)

blockNrOrHash := rpctypes.BlockNumberOrHashWithNumber(blockNr)
rets := make([]hexutil.Bytes, 0, len(args))
for _, arg := range args {
ret, err := api.Call(arg, blockNr, nil)
ret, err := api.Call(arg, blockNrOrHash, nil)
if err != nil {
return rets, err
}
Expand Down Expand Up @@ -1176,10 +1199,14 @@ func (api *PublicEthereumAPI) GetUncleByBlockNumberAndIndex(number hexutil.Uint,
}

// GetProof returns an account object with proof and any storage proofs
func (api *PublicEthereumAPI) GetProof(address common.Address, storageKeys []string, block rpctypes.BlockNumber) (*rpctypes.AccountResult, error) {
api.logger.Debug("eth_getProof", "address", address, "keys", storageKeys, "number", block)

clientCtx := api.clientCtx.WithHeight(int64(block))
func (api *PublicEthereumAPI) GetProof(address common.Address, storageKeys []string, blockNrOrHash rpctypes.BlockNumberOrHash) (*rpctypes.AccountResult, error) {
monitor := monitor.GetMonitor("eth_getProof", api.logger, api.Metrics).OnBegin()
defer monitor.OnEnd("address", address, "keys", storageKeys, "number", blockNrOrHash)
blockNum, err := api.backend.ConvertToBlockNumber(blockNrOrHash)
if err != nil {
return nil, err
}
clientCtx := api.clientCtx.WithHeight(int64(blockNum))
path := fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryAccount, address.Hex())

// query eth account at block height
Expand All @@ -1198,7 +1225,7 @@ func (api *PublicEthereumAPI) GetProof(address common.Address, storageKeys []str
req := abci.RequestQuery{
Path: fmt.Sprintf("store/%s/key", evmtypes.StoreKey),
Data: data,
Height: int64(block),
Height: int64(blockNum),
Prove: true,
}

Expand Down Expand Up @@ -1227,7 +1254,7 @@ func (api *PublicEthereumAPI) GetProof(address common.Address, storageKeys []str
req := abci.RequestQuery{
Path: fmt.Sprintf("store/%s/key", auth.StoreKey),
Data: auth.AddressStoreKey(sdk.AccAddress(address.Bytes())),
Height: int64(block),
Height: int64(blockNum),
Prove: true,
}

Expand Down
13 changes: 8 additions & 5 deletions app/rpc/namespaces/eth/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ func (pool *TxPool) initDB(api *PublicEthereumAPI) error {
if int(tx.Data.AccountNonce) != txNonce {
return fmt.Errorf("nonce[%d] in key is not equal to nonce[%d] in value", tx.Data.AccountNonce, txNonce)
}

pCurrentNonce, err := api.GetTransactionCount(address, rpctypes.PendingBlockNumber)
blockNrOrHash := rpctypes.BlockNumberOrHashWithNumber(rpctypes.PendingBlockNumber)
pCurrentNonce, err := api.GetTransactionCount(address, blockNrOrHash)
if err != nil {
return err
}
Expand Down Expand Up @@ -144,7 +144,8 @@ func broadcastTxByTxPool(api *PublicEthereumAPI, tx *evmtypes.MsgEthereumTx, txB

func (pool *TxPool) CacheAndBroadcastTx(api *PublicEthereumAPI, address common.Address, tx *evmtypes.MsgEthereumTx) error {
// get currentNonce
pCurrentNonce, err := api.GetTransactionCount(address, rpctypes.PendingBlockNumber)
blockNrOrHash := rpctypes.BlockNumberOrHashWithNumber(rpctypes.PendingBlockNumber)
pCurrentNonce, err := api.GetTransactionCount(address, blockNrOrHash)
if err != nil {
return err
}
Expand Down Expand Up @@ -318,8 +319,9 @@ func (pool *TxPool) broadcastPeriod(api *PublicEthereumAPI) {
func (pool *TxPool) broadcastPeriodCore(api *PublicEthereumAPI) {
pool.mu.Lock()
defer pool.mu.Unlock()
blockNrOrHash := rpctypes.BlockNumberOrHashWithNumber(rpctypes.PendingBlockNumber)
for address, _ := range pool.addressTxsPool {
pCurrentNonce, err := api.GetTransactionCount(address, rpctypes.PendingBlockNumber)
pCurrentNonce, err := api.GetTransactionCount(address, blockNrOrHash)
if err != nil {
pool.logger.Error(err.Error())
continue
Expand All @@ -333,8 +335,9 @@ func (pool *TxPool) broadcastPeriodCore(api *PublicEthereumAPI) {
func (pool *TxPool) broadcastOnce(api *PublicEthereumAPI) {
pool.mu.Lock()
defer pool.mu.Unlock()
blockNrOrHash := rpctypes.BlockNumberOrHashWithNumber(rpctypes.PendingBlockNumber)
for address, _ := range pool.addressTxsPool {
pCurrentNonce, err := api.GetTransactionCount(address, rpctypes.PendingBlockNumber)
pCurrentNonce, err := api.GetTransactionCount(address, blockNrOrHash)
if err != nil {
continue
}
Expand Down
97 changes: 97 additions & 0 deletions app/rpc/types/block.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package types

import (
"encoding/json"
"errors"
"fmt"
"math"
"math/big"
"strings"

"github.com/ethereum/go-ethereum/common"

"github.com/ethereum/go-ethereum/common/hexutil"
)

Expand All @@ -23,6 +27,8 @@ const (
PendingBlockNumber = BlockNumber(-1)
)

var ErrResourceNotFound = errors.New("resource not found")

// NewBlockNumber creates a new BlockNumber instance.
func NewBlockNumber(n *big.Int) BlockNumber {
return BlockNumber(n.Int64())
Expand Down Expand Up @@ -79,3 +85,94 @@ func (bn BlockNumber) TmHeight() *int64 {
height := bn.Int64()
return &height
}

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,
}
}

0 comments on commit 569c89a

Please sign in to comment.