laconicd/x/evm/keeper/grpc_query.go

399 lines
10 KiB
Go
Raw Normal View History

2021-04-17 10:00:07 +00:00
package keeper
import (
"context"
"encoding/json"
2021-04-17 10:00:07 +00:00
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
2021-04-17 10:00:07 +00:00
ethcmn "github.com/ethereum/go-ethereum/common"
ethermint "github.com/tharsis/ethermint/types"
"github.com/tharsis/ethermint/x/evm/types"
2021-04-17 10:00:07 +00:00
)
var _ types.QueryServer = Keeper{}
// Account implements the Query/Account gRPC method
2021-04-18 15:54:18 +00:00
func (k Keeper) Account(c context.Context, req *types.QueryAccountRequest) (*types.QueryAccountResponse, error) {
2021-04-17 10:00:07 +00:00
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if err := ethermint.ValidateAddress(req.Address); err != nil {
2021-04-17 10:00:07 +00:00
return nil, status.Error(
codes.InvalidArgument, err.Error(),
2021-04-17 10:00:07 +00:00
)
}
addr := ethcmn.HexToAddress(req.Address)
ctx := sdk.UnwrapSDKContext(c)
k.WithContext(ctx)
2021-04-17 10:00:07 +00:00
return &types.QueryAccountResponse{
Balance: k.GetBalance(addr).String(),
CodeHash: k.GetCodeHash(addr).Hex(),
Nonce: k.GetNonce(addr),
2021-04-17 10:00:07 +00:00
}, nil
}
2021-04-18 15:54:18 +00:00
func (k Keeper) CosmosAccount(c context.Context, req *types.QueryCosmosAccountRequest) (*types.QueryCosmosAccountResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if err := ethermint.ValidateAddress(req.Address); err != nil {
2021-04-18 15:54:18 +00:00
return nil, status.Error(
codes.InvalidArgument, err.Error(),
2021-04-18 15:54:18 +00:00
)
}
ctx := sdk.UnwrapSDKContext(c)
k.WithContext(ctx)
2021-04-18 15:54:18 +00:00
ethAddr := ethcmn.HexToAddress(req.Address)
cosmosAddr := sdk.AccAddress(ethAddr.Bytes())
2021-04-18 15:54:18 +00:00
account := k.accountKeeper.GetAccount(ctx, cosmosAddr)
2021-04-18 15:54:18 +00:00
res := types.QueryCosmosAccountResponse{
CosmosAddress: cosmosAddr.String(),
2021-04-18 15:54:18 +00:00
}
if account != nil {
res.Sequence = account.GetSequence()
res.AccountNumber = account.GetAccountNumber()
2021-04-18 15:54:18 +00:00
}
2021-04-18 15:54:18 +00:00
return &res, nil
}
func (k Keeper) ValidatorAccount(c context.Context, req *types.QueryValidatorAccountRequest) (*types.QueryValidatorAccountResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
consAddr, err := sdk.ConsAddressFromBech32(req.ConsAddress)
if err != nil {
return nil, status.Error(
codes.InvalidArgument, err.Error(),
)
}
ctx := sdk.UnwrapSDKContext(c)
k.WithContext(ctx)
validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, consAddr)
if !found {
return nil, nil
}
accAddr := sdk.AccAddress(validator.GetOperator())
res := types.QueryValidatorAccountResponse{
AccountAddress: accAddr.String(),
}
account := k.accountKeeper.GetAccount(ctx, accAddr)
if account != nil {
res.Sequence = account.GetSequence()
res.AccountNumber = account.GetAccountNumber()
}
return &res, nil
}
2021-04-17 10:00:07 +00:00
// Balance implements the Query/Balance gRPC method
2021-04-18 15:54:18 +00:00
func (k Keeper) Balance(c context.Context, req *types.QueryBalanceRequest) (*types.QueryBalanceResponse, error) {
2021-04-17 10:00:07 +00:00
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if err := ethermint.ValidateAddress(req.Address); err != nil {
2021-04-17 10:00:07 +00:00
return nil, status.Error(
codes.InvalidArgument,
types.ErrZeroAddress.Error(),
)
}
ctx := sdk.UnwrapSDKContext(c)
k.WithContext(ctx)
2021-04-17 10:00:07 +00:00
balanceInt := k.GetBalance(ethcmn.HexToAddress(req.Address))
2021-04-17 10:00:07 +00:00
return &types.QueryBalanceResponse{
Balance: balanceInt.String(),
2021-04-17 10:00:07 +00:00
}, nil
}
// Storage implements the Query/Storage gRPC method
2021-04-18 15:54:18 +00:00
func (k Keeper) Storage(c context.Context, req *types.QueryStorageRequest) (*types.QueryStorageResponse, error) {
2021-04-17 10:00:07 +00:00
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if err := ethermint.ValidateAddress(req.Address); err != nil {
2021-04-17 10:00:07 +00:00
return nil, status.Error(
codes.InvalidArgument,
types.ErrZeroAddress.Error(),
)
}
if ethermint.IsEmptyHash(req.Key) {
return nil, status.Errorf(
codes.InvalidArgument,
types.ErrEmptyHash.Error(),
)
}
2021-04-17 10:00:07 +00:00
ctx := sdk.UnwrapSDKContext(c)
k.WithContext(ctx)
2021-04-17 10:00:07 +00:00
address := ethcmn.HexToAddress(req.Address)
key := ethcmn.HexToHash(req.Key)
state := k.GetState(address, key)
stateHex := state.Hex()
if ethermint.IsEmptyHash(stateHex) {
return nil, status.Error(
codes.NotFound, "contract code not found for given address",
)
}
2021-04-17 10:00:07 +00:00
return &types.QueryStorageResponse{
Value: stateHex,
2021-04-17 10:00:07 +00:00
}, nil
}
// Code implements the Query/Code gRPC method
2021-04-18 15:54:18 +00:00
func (k Keeper) Code(c context.Context, req *types.QueryCodeRequest) (*types.QueryCodeResponse, error) {
2021-04-17 10:00:07 +00:00
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if err := ethermint.ValidateAddress(req.Address); err != nil {
2021-04-17 10:00:07 +00:00
return nil, status.Error(
codes.InvalidArgument,
types.ErrZeroAddress.Error(),
)
}
ctx := sdk.UnwrapSDKContext(c)
k.WithContext(ctx)
2021-04-17 10:00:07 +00:00
address := ethcmn.HexToAddress(req.Address)
code := k.GetCode(address)
2021-04-17 10:00:07 +00:00
return &types.QueryCodeResponse{
Code: code,
}, nil
}
// TxLogs implements the Query/TxLogs gRPC method
2021-04-18 15:54:18 +00:00
func (k Keeper) TxLogs(c context.Context, req *types.QueryTxLogsRequest) (*types.QueryTxLogsResponse, error) {
2021-04-17 10:00:07 +00:00
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if ethermint.IsEmptyHash(req.Hash) {
2021-04-17 10:00:07 +00:00
return nil, status.Error(
codes.InvalidArgument,
types.ErrEmptyHash.Error(),
)
}
ctx := sdk.UnwrapSDKContext(c)
k.WithContext(ctx)
2021-04-17 10:00:07 +00:00
hash := ethcmn.HexToHash(req.Hash)
logs := k.GetTxLogs(hash)
2021-04-17 10:00:07 +00:00
return &types.QueryTxLogsResponse{
Logs: types.NewLogsFromEth(logs),
2021-04-17 10:00:07 +00:00
}, nil
}
// BlockLogs implements the Query/BlockLogs gRPC method
func (k Keeper) BlockLogs(c context.Context, req *types.QueryBlockLogsRequest) (*types.QueryBlockLogsResponse, error) {
2021-04-18 15:54:18 +00:00
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if ethermint.IsEmptyHash(req.Hash) {
2021-04-18 15:54:18 +00:00
return nil, status.Error(
codes.InvalidArgument,
types.ErrEmptyHash.Error(),
)
}
ctx := sdk.UnwrapSDKContext(c)
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixLogs)
txLogs := []types.TransactionLogs{}
2021-04-18 15:54:18 +00:00
pageRes, err := query.FilteredPaginate(store, req.Pagination, func(_, value []byte, accumulate bool) (bool, error) {
var txLog types.TransactionLogs
k.cdc.MustUnmarshal(value, &txLog)
2021-04-18 15:54:18 +00:00
if len(txLog.Logs) > 0 && txLog.Logs[0].BlockHash == req.Hash {
if accumulate {
txLogs = append(txLogs, txLog)
}
return true, nil
}
2021-04-17 10:00:07 +00:00
return false, nil
})
2021-04-17 10:00:07 +00:00
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
2021-04-17 10:00:07 +00:00
return &types.QueryBlockLogsResponse{
TxLogs: txLogs,
Pagination: pageRes,
2021-04-17 10:00:07 +00:00
}, nil
}
// BlockBloom implements the Query/BlockBloom gRPC method
func (k Keeper) BlockBloom(c context.Context, _ *types.QueryBlockBloomRequest) (*types.QueryBlockBloomResponse, error) {
2021-04-17 10:00:07 +00:00
ctx := sdk.UnwrapSDKContext(c)
bloom, found := k.GetBlockBloom(ctx, ctx.BlockHeight())
2021-04-17 10:00:07 +00:00
if !found {
2021-04-18 15:54:18 +00:00
return nil, status.Error(
codes.NotFound, types.ErrBloomNotFound.Error(),
2021-04-17 10:00:07 +00:00
)
}
return &types.QueryBlockBloomResponse{
Bloom: bloom.Bytes(),
}, nil
}
// Params implements the Query/Params gRPC method
func (k Keeper) Params(c context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) {
2021-04-17 10:00:07 +00:00
ctx := sdk.UnwrapSDKContext(c)
2021-04-18 15:54:18 +00:00
params := k.GetParams(ctx)
2021-04-17 10:00:07 +00:00
return &types.QueryParamsResponse{
Params: params,
}, nil
}
2021-04-18 15:54:18 +00:00
// ChainConfig implements the Query/ChainConfig gRPC method
func (k Keeper) ChainConfig(c context.Context, _ *types.QueryChainConfigRequest) (*types.QueryChainConfigResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
cfg, found := k.GetChainConfig(ctx)
if !found {
return nil, status.Error(codes.NotFound, types.ErrChainConfigNotFound.Error())
}
return &types.QueryChainConfigResponse{
Config: cfg,
}, nil
}
2021-04-18 15:54:18 +00:00
// StaticCall implements Query/StaticCall gRPCP method
func (k Keeper) StaticCall(c context.Context, req *types.QueryStaticCallRequest) (*types.QueryStaticCallResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
// ctx := sdk.UnwrapSDKContext(c)
// k.WithContext(ctx)
// // parse the chainID from a string to a base-10 integer
// chainIDEpoch, err := ethermint.ParseChainID(ctx.ChainID())
// if err != nil {
// return nil, status.Error(codes.Internal, err.Error())
// }
// txHash := tmtypes.Tx(ctx.TxBytes()).Hash()
// ethHash := ethcmn.BytesToHash(txHash)
// var recipient *ethcmn.Address
// if len(req.Address) > 0 {
// addr := ethcmn.HexToAddress(req.Address)
// recipient = &addr
// }
// so := k.GetOrNewStateObject(*recipient)
// sender := ethcmn.HexToAddress("0xaDd00275E3d9d213654Ce5223f0FADE8b106b707")
// msg := types.NewTx(
// chainIDEpoch, so.Nonce(), recipient, big.NewInt(0), 100000000, big.NewInt(0), req.Input, nil,
// )
// msg.From = sender.Hex()
// if err := msg.ValidateBasic(); err != nil {
// return nil, status.Error(codes.Internal, err.Error())
// }
// ethMsg, err := msg.AsMessage()
// if err != nil {
// return nil, status.Error(codes.Internal, err.Error())
// }
// st := &types.StateTransition{
// Message: ethMsg,
// Csdb: k.WithContext(ctx),
// ChainID: chainIDEpoch,
// TxHash: &ethHash,
// Simulate: ctx.IsCheckTx(),
// Debug: false,
// }
// config, found := k.GetChainConfig(ctx)
// if !found {
// return nil, status.Error(codes.Internal, types.ErrChainConfigNotFound.Error())
// }
// ret, err := st.StaticCall(ctx, config)
// if err != nil {
// return nil, status.Error(codes.Internal, err.Error())
// }
// return &types.QueryStaticCallResponse{Data: ret}, nil
return nil, nil
2021-04-18 15:54:18 +00:00
}
// EthCall implements eth_call rpc api.
func (k Keeper) EthCall(c context.Context, req *types.EthCallRequest) (*types.MsgEthereumTxResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
k.WithContext(ctx)
var args types.CallArgs
err := json.Unmarshal(req.Args, &args)
if err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
msg := args.ToMessage(uint64(ethermint.DefaultRPCGasLimit))
cfg, found := k.GetChainConfig(ctx)
if !found {
return nil, status.Error(codes.Internal, types.ErrChainConfigNotFound.Error())
}
ethCfg := cfg.EthereumConfig(k.eip155ChainID)
evm := k.NewEVM(msg, ethCfg)
res, err := k.ApplyMessage(evm, msg, ethCfg)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
// ApplyMessage don't handle gas refund, let's do it here
refund := k.GasToRefund(res.GasUsed)
res.GasUsed -= refund
return res, nil
}