forked from evmos/ethermint
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(rpc): restructure JSON-RPC APIs (evmos#1218)
* move non api methods from eth/api.go to evm_backend: ClientCtx, QueryClient, Ctx, getBlockNumber, getTransactionByBlockAndIndex, doCall * organize eth/api.go into sections and move backend logic to dedicated files * remove unnecesary comment * move resend to the backend * refractor eth api * refractor debug namespace * refactor miner namespace * refactor personal namespace * update transactionReceipt from upstream * update getBlockByNumber from upstream * update getBalance from upstream * update getProof from upstream * update getBalance from upstream * fix linter * remove duplicated import * remove duplicated import * fix backend tests * fix lint * fix duplicated imports * fix linter * reorganize blocks * backend folder refractor * remove unnecessary file * remove duplicate import Co-authored-by: Freddy Caceres <facs95@gmail.com>
- Loading branch information
Showing
20 changed files
with
2,891 additions
and
2,544 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
package backend | ||
|
||
import ( | ||
"fmt" | ||
"math" | ||
"math/big" | ||
|
||
sdkmath "cosmossdk.io/math" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/common/hexutil" | ||
rpctypes "github.com/evmos/ethermint/rpc/types" | ||
evmtypes "github.com/evmos/ethermint/x/evm/types" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
// GetCode returns the contract code at the given address and block number. | ||
func (b *Backend) GetCode(address common.Address, blockNrOrHash rpctypes.BlockNumberOrHash) (hexutil.Bytes, error) { | ||
blockNum, err := b.GetBlockNumber(blockNrOrHash) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
req := &evmtypes.QueryCodeRequest{ | ||
Address: address.String(), | ||
} | ||
|
||
res, err := b.queryClient.Code(rpctypes.ContextWithHeight(blockNum.Int64()), req) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return res.Code, nil | ||
} | ||
|
||
// GetProof returns an account object with proof and any storage proofs | ||
func (b *Backend) GetProof(address common.Address, storageKeys []string, blockNrOrHash rpctypes.BlockNumberOrHash) (*rpctypes.AccountResult, error) { | ||
blockNum, err := b.GetBlockNumber(blockNrOrHash) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
height := blockNum.Int64() | ||
_, err = b.GetTendermintBlockByNumber(blockNum) | ||
if err != nil { | ||
// Get 'latest' proof if query is in the future | ||
// this imitates geth behavior | ||
height = 0 | ||
} | ||
ctx := rpctypes.ContextWithHeight(height) | ||
|
||
// if the height is equal to zero, meaning the query condition of the block is either "pending" or "latest" | ||
if height == 0 { | ||
bn, err := b.BlockNumber() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if bn > math.MaxInt64 { | ||
return nil, fmt.Errorf("not able to query block number greater than MaxInt64") | ||
} | ||
|
||
height = int64(bn) | ||
} | ||
|
||
clientCtx := b.clientCtx.WithHeight(height) | ||
|
||
// query storage proofs | ||
storageProofs := make([]rpctypes.StorageResult, len(storageKeys)) | ||
|
||
for i, key := range storageKeys { | ||
hexKey := common.HexToHash(key) | ||
valueBz, proof, err := b.queryClient.GetProof(clientCtx, evmtypes.StoreKey, evmtypes.StateKey(address, hexKey.Bytes())) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// check for proof | ||
var proofStr string | ||
if proof != nil { | ||
proofStr = proof.String() | ||
} | ||
|
||
storageProofs[i] = rpctypes.StorageResult{ | ||
Key: key, | ||
Value: (*hexutil.Big)(new(big.Int).SetBytes(valueBz)), | ||
Proof: []string{proofStr}, | ||
} | ||
} | ||
|
||
// query EVM account | ||
req := &evmtypes.QueryAccountRequest{ | ||
Address: address.String(), | ||
} | ||
|
||
res, err := b.queryClient.Account(ctx, req) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// query account proofs | ||
accountKey := authtypes.AddressStoreKey(sdk.AccAddress(address.Bytes())) | ||
_, proof, err := b.queryClient.GetProof(clientCtx, authtypes.StoreKey, accountKey) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// check for proof | ||
var accProofStr string | ||
if proof != nil { | ||
accProofStr = proof.String() | ||
} | ||
|
||
balance, ok := sdkmath.NewIntFromString(res.Balance) | ||
if !ok { | ||
return nil, errors.New("invalid balance") | ||
} | ||
|
||
return &rpctypes.AccountResult{ | ||
Address: address, | ||
AccountProof: []string{accProofStr}, | ||
Balance: (*hexutil.Big)(balance.BigInt()), | ||
CodeHash: common.HexToHash(res.CodeHash), | ||
Nonce: hexutil.Uint64(res.Nonce), | ||
StorageHash: common.Hash{}, // NOTE: Ethermint doesn't have a storage hash. TODO: implement? | ||
StorageProof: storageProofs, | ||
}, nil | ||
} | ||
|
||
// GetStorageAt returns the contract storage at the given address, block number, and key. | ||
func (b *Backend) GetStorageAt(address common.Address, key string, blockNrOrHash rpctypes.BlockNumberOrHash) (hexutil.Bytes, error) { | ||
blockNum, err := b.GetBlockNumber(blockNrOrHash) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
req := &evmtypes.QueryStorageRequest{ | ||
Address: address.String(), | ||
Key: key, | ||
} | ||
|
||
res, err := b.queryClient.Storage(rpctypes.ContextWithHeight(blockNum.Int64()), req) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
value := common.HexToHash(res.Value) | ||
return value.Bytes(), nil | ||
} | ||
|
||
// GetBalance returns the provided account's balance up to the provided block number. | ||
func (b *Backend) GetBalance(address common.Address, blockNrOrHash rpctypes.BlockNumberOrHash) (*hexutil.Big, error) { | ||
blockNum, err := b.GetBlockNumber(blockNrOrHash) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
req := &evmtypes.QueryBalanceRequest{ | ||
Address: address.String(), | ||
} | ||
|
||
_, err = b.GetTendermintBlockByNumber(blockNum) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
res, err := b.queryClient.Balance(rpctypes.ContextWithHeight(blockNum.Int64()), req) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
val, ok := sdkmath.NewIntFromString(res.Balance) | ||
if !ok { | ||
return nil, errors.New("invalid balance") | ||
} | ||
|
||
// balance can only be negative in case of pruned node | ||
if val.IsNegative() { | ||
return nil, errors.New("couldn't fetch balance. Node state is pruned") | ||
} | ||
|
||
return (*hexutil.Big)(val.BigInt()), nil | ||
} | ||
|
||
// GetTransactionCount returns the number of transactions at the given address up to the given block number. | ||
func (b *Backend) GetTransactionCount(address common.Address, blockNum rpctypes.BlockNumber) (*hexutil.Uint64, error) { | ||
// Get nonce (sequence) from account | ||
from := sdk.AccAddress(address.Bytes()) | ||
accRet := b.clientCtx.AccountRetriever | ||
|
||
err := accRet.EnsureExists(b.clientCtx, from) | ||
if err != nil { | ||
// account doesn't exist yet, return 0 | ||
n := hexutil.Uint64(0) | ||
return &n, nil | ||
} | ||
|
||
includePending := blockNum == rpctypes.EthPendingBlockNumber | ||
nonce, err := b.getAccountNonce(address, includePending, blockNum.Int64(), b.logger) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
n := hexutil.Uint64(nonce) | ||
return &n, nil | ||
} |
Oops, something went wrong.