2021-04-17 10:00:07 +00:00
|
|
|
package keeper
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-04-18 15:54:18 +00:00
|
|
|
"math/big"
|
2021-04-17 10:00:07 +00:00
|
|
|
|
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
"google.golang.org/grpc/status"
|
|
|
|
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2021-04-18 15:54:18 +00:00
|
|
|
tmtypes "github.com/tendermint/tendermint/types"
|
2021-04-17 10:00:07 +00:00
|
|
|
|
|
|
|
ethcmn "github.com/ethereum/go-ethereum/common"
|
|
|
|
|
2021-04-18 15:54:18 +00:00
|
|
|
"github.com/cosmos/ethermint/metrics"
|
2021-04-17 10:00:07 +00:00
|
|
|
ethermint "github.com/cosmos/ethermint/types"
|
|
|
|
"github.com/cosmos/ethermint/x/evm/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
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) {
|
|
|
|
metrics.ReportFuncCall(k.svcTags)
|
|
|
|
doneFn := metrics.ReportFuncTiming(k.svcTags)
|
|
|
|
defer doneFn()
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
if req == nil {
|
2021-04-18 15:54:18 +00:00
|
|
|
metrics.ReportFuncError(k.svcTags)
|
2021-04-17 10:00:07 +00:00
|
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
|
|
}
|
|
|
|
|
2021-04-18 15:54:18 +00:00
|
|
|
if types.IsZeroAddress(req.Address) {
|
|
|
|
metrics.ReportFuncError(k.svcTags)
|
2021-04-17 10:00:07 +00:00
|
|
|
return nil, status.Error(
|
|
|
|
codes.InvalidArgument,
|
|
|
|
types.ErrZeroAddress.Error(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
2021-04-18 15:54:18 +00:00
|
|
|
so := k.GetOrNewStateObject(ctx, ethcmn.HexToAddress(req.Address))
|
2021-04-17 10:00:07 +00:00
|
|
|
balance, err := ethermint.MarshalBigInt(so.Balance())
|
|
|
|
if err != nil {
|
2021-04-18 15:54:18 +00:00
|
|
|
metrics.ReportFuncError(k.svcTags)
|
2021-04-17 10:00:07 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &types.QueryAccountResponse{
|
|
|
|
Balance: balance,
|
|
|
|
CodeHash: so.CodeHash(),
|
|
|
|
Nonce: so.Nonce(),
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2021-04-18 15:54:18 +00:00
|
|
|
func (k Keeper) CosmosAccount(c context.Context, req *types.QueryCosmosAccountRequest) (*types.QueryCosmosAccountResponse, error) {
|
|
|
|
metrics.ReportFuncCall(k.svcTags)
|
|
|
|
doneFn := metrics.ReportFuncTiming(k.svcTags)
|
|
|
|
defer doneFn()
|
|
|
|
|
|
|
|
if req == nil {
|
|
|
|
metrics.ReportFuncError(k.svcTags)
|
|
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
|
|
}
|
|
|
|
|
|
|
|
if types.IsZeroAddress(req.Address) {
|
|
|
|
metrics.ReportFuncError(k.svcTags)
|
|
|
|
return nil, status.Error(
|
|
|
|
codes.InvalidArgument,
|
|
|
|
types.ErrZeroAddress.Error(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
|
|
|
|
|
|
ethStr := req.Address
|
|
|
|
ethAddr := ethcmn.FromHex(ethStr)
|
|
|
|
|
|
|
|
ethToCosmosAddr := sdk.AccAddress(ethAddr[:]).String()
|
|
|
|
cosmosToEthAddr, _ := sdk.AccAddressFromBech32(ethToCosmosAddr)
|
|
|
|
|
|
|
|
acc := k.accountKeeper.GetAccount(ctx, cosmosToEthAddr)
|
|
|
|
res := types.QueryCosmosAccountResponse{
|
|
|
|
CosmosAddress: cosmosToEthAddr.String(),
|
|
|
|
}
|
|
|
|
if acc != nil {
|
|
|
|
res.Sequence = acc.GetSequence()
|
|
|
|
res.AccountNumber = acc.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) {
|
|
|
|
metrics.ReportFuncCall(k.svcTags)
|
|
|
|
doneFn := metrics.ReportFuncTiming(k.svcTags)
|
|
|
|
defer doneFn()
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
if req == nil {
|
2021-04-18 15:54:18 +00:00
|
|
|
metrics.ReportFuncError(k.svcTags)
|
2021-04-17 10:00:07 +00:00
|
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
|
|
}
|
|
|
|
|
2021-04-18 15:54:18 +00:00
|
|
|
if types.IsZeroAddress(req.Address) {
|
|
|
|
metrics.ReportFuncError(k.svcTags)
|
2021-04-17 10:00:07 +00:00
|
|
|
return nil, status.Error(
|
|
|
|
codes.InvalidArgument,
|
|
|
|
types.ErrZeroAddress.Error(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
|
|
|
2021-04-18 15:54:18 +00:00
|
|
|
balanceInt := k.GetBalance(ctx, ethcmn.HexToAddress(req.Address))
|
2021-04-17 10:00:07 +00:00
|
|
|
balance, err := ethermint.MarshalBigInt(balanceInt)
|
|
|
|
if err != nil {
|
2021-04-18 15:54:18 +00:00
|
|
|
metrics.ReportFuncError(k.svcTags)
|
2021-04-17 10:00:07 +00:00
|
|
|
return nil, status.Error(
|
|
|
|
codes.Internal,
|
|
|
|
"failed to marshal big.Int to string",
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &types.QueryBalanceResponse{
|
|
|
|
Balance: balance,
|
|
|
|
}, 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) {
|
|
|
|
metrics.ReportFuncCall(k.svcTags)
|
|
|
|
doneFn := metrics.ReportFuncTiming(k.svcTags)
|
|
|
|
defer doneFn()
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
if req == nil {
|
2021-04-18 15:54:18 +00:00
|
|
|
metrics.ReportFuncError(k.svcTags)
|
2021-04-17 10:00:07 +00:00
|
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
|
|
}
|
|
|
|
|
2021-04-18 15:54:18 +00:00
|
|
|
if types.IsZeroAddress(req.Address) {
|
|
|
|
metrics.ReportFuncError(k.svcTags)
|
2021-04-17 10:00:07 +00:00
|
|
|
return nil, status.Error(
|
|
|
|
codes.InvalidArgument,
|
|
|
|
types.ErrZeroAddress.Error(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
|
|
|
|
|
|
address := ethcmn.HexToAddress(req.Address)
|
|
|
|
key := ethcmn.HexToHash(req.Key)
|
|
|
|
|
2021-04-18 15:54:18 +00:00
|
|
|
state := k.GetState(ctx, address, key)
|
2021-04-17 10:00:07 +00:00
|
|
|
|
|
|
|
return &types.QueryStorageResponse{
|
|
|
|
Value: state.String(),
|
|
|
|
}, 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) {
|
|
|
|
metrics.ReportFuncCall(k.svcTags)
|
|
|
|
doneFn := metrics.ReportFuncTiming(k.svcTags)
|
|
|
|
defer doneFn()
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
if req == nil {
|
2021-04-18 15:54:18 +00:00
|
|
|
metrics.ReportFuncError(k.svcTags)
|
2021-04-17 10:00:07 +00:00
|
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
|
|
}
|
|
|
|
|
2021-04-18 15:54:18 +00:00
|
|
|
if types.IsZeroAddress(req.Address) {
|
|
|
|
metrics.ReportFuncError(k.svcTags)
|
2021-04-17 10:00:07 +00:00
|
|
|
return nil, status.Error(
|
|
|
|
codes.InvalidArgument,
|
|
|
|
types.ErrZeroAddress.Error(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
|
|
|
|
|
|
address := ethcmn.HexToAddress(req.Address)
|
2021-04-18 15:54:18 +00:00
|
|
|
code := k.GetCode(ctx, 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) {
|
|
|
|
metrics.ReportFuncCall(k.svcTags)
|
|
|
|
doneFn := metrics.ReportFuncTiming(k.svcTags)
|
|
|
|
defer doneFn()
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
if req == nil {
|
2021-04-18 15:54:18 +00:00
|
|
|
metrics.ReportFuncError(k.svcTags)
|
2021-04-17 10:00:07 +00:00
|
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
|
|
}
|
|
|
|
|
|
|
|
if types.IsEmptyHash(req.Hash) {
|
2021-04-18 15:54:18 +00:00
|
|
|
metrics.ReportFuncError(k.svcTags)
|
2021-04-17 10:00:07 +00:00
|
|
|
return nil, status.Error(
|
|
|
|
codes.InvalidArgument,
|
|
|
|
types.ErrEmptyHash.Error(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
|
|
|
|
|
|
hash := ethcmn.HexToHash(req.Hash)
|
2021-04-18 15:54:18 +00:00
|
|
|
logs, err := k.GetLogs(ctx, hash)
|
2021-04-17 10:00:07 +00:00
|
|
|
if err != nil {
|
2021-04-18 15:54:18 +00:00
|
|
|
metrics.ReportFuncError(k.svcTags)
|
2021-04-17 10:00:07 +00:00
|
|
|
return nil, status.Error(
|
|
|
|
codes.Internal,
|
|
|
|
err.Error(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &types.QueryTxLogsResponse{
|
|
|
|
Logs: types.NewTransactionLogsFromEth(hash, logs).Logs,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2021-04-18 15:54:18 +00:00
|
|
|
// TxReceipt implements the Query/TxReceipt gRPC method
|
|
|
|
func (k Keeper) TxReceipt(c context.Context, req *types.QueryTxReceiptRequest) (*types.QueryTxReceiptResponse, error) {
|
|
|
|
metrics.ReportFuncCall(k.svcTags)
|
|
|
|
doneFn := metrics.ReportFuncTiming(k.svcTags)
|
|
|
|
defer doneFn()
|
|
|
|
|
|
|
|
if req == nil {
|
|
|
|
metrics.ReportFuncError(k.svcTags)
|
|
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
|
|
}
|
|
|
|
|
|
|
|
if types.IsEmptyHash(req.Hash) {
|
|
|
|
metrics.ReportFuncError(k.svcTags)
|
|
|
|
return nil, status.Error(
|
|
|
|
codes.InvalidArgument,
|
|
|
|
types.ErrEmptyHash.Error(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
|
|
|
|
|
|
hash := ethcmn.HexToHash(req.Hash)
|
|
|
|
receipt, found := k.GetTxReceiptFromHash(ctx, hash)
|
|
|
|
if !found {
|
|
|
|
metrics.ReportFuncError(k.svcTags)
|
|
|
|
return nil, status.Error(
|
|
|
|
codes.NotFound, types.ErrTxReceiptNotFound.Error(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &types.QueryTxReceiptResponse{
|
|
|
|
Receipt: receipt,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TxReceiptsByBlockHeight implements the Query/TxReceiptsByBlockHeight gRPC method
|
|
|
|
func (k Keeper) TxReceiptsByBlockHeight(c context.Context, req *types.QueryTxReceiptsByBlockHeightRequest) (*types.QueryTxReceiptsByBlockHeightResponse, error) {
|
|
|
|
metrics.ReportFuncCall(k.svcTags)
|
|
|
|
doneFn := metrics.ReportFuncTiming(k.svcTags)
|
|
|
|
defer doneFn()
|
|
|
|
|
|
|
|
if req == nil {
|
|
|
|
metrics.ReportFuncError(k.svcTags)
|
|
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
|
|
|
|
|
|
receipts := k.GetTxReceiptsByBlockHeight(ctx, req.Height)
|
|
|
|
return &types.QueryTxReceiptsByBlockHeightResponse{
|
|
|
|
Receipts: receipts,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TxReceiptsByBlockHash implements the Query/TxReceiptsByBlockHash gRPC method
|
|
|
|
func (k Keeper) TxReceiptsByBlockHash(c context.Context, req *types.QueryTxReceiptsByBlockHashRequest) (*types.QueryTxReceiptsByBlockHashResponse, error) {
|
|
|
|
metrics.ReportFuncCall(k.svcTags)
|
|
|
|
doneFn := metrics.ReportFuncTiming(k.svcTags)
|
|
|
|
defer doneFn()
|
|
|
|
|
|
|
|
if req == nil {
|
|
|
|
metrics.ReportFuncError(k.svcTags)
|
|
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
|
|
}
|
|
|
|
|
|
|
|
if types.IsEmptyHash(req.Hash) {
|
|
|
|
metrics.ReportFuncError(k.svcTags)
|
|
|
|
return nil, status.Error(
|
|
|
|
codes.InvalidArgument,
|
|
|
|
types.ErrEmptyHash.Error(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
|
|
|
|
|
|
hash := ethcmn.HexToHash(req.Hash)
|
|
|
|
receipts := k.GetTxReceiptsByBlockHash(ctx, hash)
|
|
|
|
|
|
|
|
return &types.QueryTxReceiptsByBlockHashResponse{
|
|
|
|
Receipts: receipts,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
// BlockLogs implements the Query/BlockLogs gRPC method
|
2021-04-18 15:54:18 +00:00
|
|
|
func (k Keeper) BlockLogs(c context.Context, req *types.QueryBlockLogsRequest) (*types.QueryBlockLogsResponse, error) {
|
|
|
|
metrics.ReportFuncCall(k.svcTags)
|
|
|
|
doneFn := metrics.ReportFuncTiming(k.svcTags)
|
|
|
|
defer doneFn()
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
if req == nil {
|
2021-04-18 15:54:18 +00:00
|
|
|
metrics.ReportFuncError(k.svcTags)
|
2021-04-17 10:00:07 +00:00
|
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
|
|
}
|
|
|
|
|
|
|
|
if types.IsEmptyHash(req.Hash) {
|
2021-04-18 15:54:18 +00:00
|
|
|
metrics.ReportFuncError(k.svcTags)
|
2021-04-17 10:00:07 +00:00
|
|
|
return nil, status.Error(
|
|
|
|
codes.InvalidArgument,
|
|
|
|
types.ErrEmptyHash.Error(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
|
|
|
2021-04-18 15:54:18 +00:00
|
|
|
txLogs := k.GetAllTxLogs(ctx)
|
2021-04-17 10:00:07 +00:00
|
|
|
|
|
|
|
return &types.QueryBlockLogsResponse{
|
|
|
|
TxLogs: txLogs,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// BlockBloom implements the Query/BlockBloom gRPC method
|
2021-04-18 15:54:18 +00:00
|
|
|
func (k Keeper) BlockBloom(c context.Context, req *types.QueryBlockBloomRequest) (*types.QueryBlockBloomResponse, error) {
|
|
|
|
metrics.ReportFuncCall(k.svcTags)
|
|
|
|
doneFn := metrics.ReportFuncTiming(k.svcTags)
|
|
|
|
defer doneFn()
|
|
|
|
|
|
|
|
if req == nil {
|
|
|
|
metrics.ReportFuncError(k.svcTags)
|
|
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
|
|
}
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
|
|
|
2021-04-18 15:54:18 +00:00
|
|
|
height := ctx.BlockHeight()
|
|
|
|
if setHeight := req.Height; setHeight > 0 {
|
|
|
|
height = setHeight
|
|
|
|
}
|
|
|
|
|
|
|
|
bloom, found := k.GetBlockBloom(ctx, height)
|
2021-04-17 10:00:07 +00:00
|
|
|
if !found {
|
2021-04-18 15:54:18 +00:00
|
|
|
metrics.ReportFuncError(k.svcTags)
|
|
|
|
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
|
2021-04-18 15:54:18 +00:00
|
|
|
func (k Keeper) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) {
|
|
|
|
metrics.ReportFuncCall(k.svcTags)
|
|
|
|
doneFn := metrics.ReportFuncTiming(k.svcTags)
|
|
|
|
defer doneFn()
|
|
|
|
|
|
|
|
if req == nil {
|
|
|
|
metrics.ReportFuncError(k.svcTags)
|
|
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
|
|
// 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)
|
|
|
|
|
|
|
|
// parse the chainID from a string to a base-10 integer
|
|
|
|
chainIDEpoch, err := ethermint.ParseChainID(ctx.ChainID())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
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(ctx, *recipient)
|
|
|
|
sender := ethcmn.HexToAddress("0xaDd00275E3d9d213654Ce5223f0FADE8b106b707")
|
|
|
|
|
|
|
|
st := &types.StateTransition{
|
|
|
|
AccountNonce: so.Nonce(),
|
|
|
|
Price: new(big.Int).SetBytes(big.NewInt(0).Bytes()),
|
|
|
|
GasLimit: 100000000,
|
|
|
|
Recipient: recipient,
|
|
|
|
Amount: new(big.Int).SetBytes(big.NewInt(0).Bytes()),
|
|
|
|
Payload: req.Input,
|
|
|
|
Csdb: k.CommitStateDB.WithContext(ctx),
|
|
|
|
ChainID: chainIDEpoch,
|
|
|
|
TxHash: ðHash,
|
|
|
|
Sender: sender,
|
|
|
|
Simulate: ctx.IsCheckTx(),
|
|
|
|
}
|
|
|
|
|
|
|
|
config, found := k.GetChainConfig(ctx)
|
|
|
|
if !found {
|
|
|
|
return nil, types.ErrChainConfigNotFound
|
|
|
|
}
|
|
|
|
|
|
|
|
ret, err := st.StaticCall(ctx, config)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &types.QueryStaticCallResponse{Data: ret}, nil
|
|
|
|
}
|