github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/app/rpc/namespaces/eth/api.go (about) 1 package eth 2 3 import ( 4 "bytes" 5 "context" 6 "crypto/sha256" 7 "encoding/json" 8 "errors" 9 "fmt" 10 "math/big" 11 "strconv" 12 "sync" 13 "time" 14 15 "github.com/ethereum/go-ethereum/accounts" 16 "github.com/ethereum/go-ethereum/accounts/keystore" 17 "github.com/ethereum/go-ethereum/common" 18 "github.com/ethereum/go-ethereum/common/hexutil" 19 ethtypes "github.com/ethereum/go-ethereum/core/types" 20 "github.com/ethereum/go-ethereum/crypto" 21 "github.com/ethereum/go-ethereum/rpc" 22 lru "github.com/hashicorp/golang-lru" 23 "github.com/spf13/viper" 24 25 appconfig "github.com/fibonacci-chain/fbc/app/config" 26 "github.com/fibonacci-chain/fbc/libs/tendermint/mempool" 27 28 "github.com/fibonacci-chain/fbc/app/config" 29 "github.com/fibonacci-chain/fbc/app/crypto/ethsecp256k1" 30 "github.com/fibonacci-chain/fbc/app/crypto/hd" 31 "github.com/fibonacci-chain/fbc/app/rpc/backend" 32 "github.com/fibonacci-chain/fbc/app/rpc/monitor" 33 "github.com/fibonacci-chain/fbc/app/rpc/namespaces/eth/simulation" 34 rpctypes "github.com/fibonacci-chain/fbc/app/rpc/types" 35 "github.com/fibonacci-chain/fbc/app/types" 36 ethermint "github.com/fibonacci-chain/fbc/app/types" 37 "github.com/fibonacci-chain/fbc/app/utils" 38 clientcontext "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/context" 39 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/flags" 40 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec" 41 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/crypto/keys" 42 cmserver "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/server" 43 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/mpt" 44 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 45 sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors" 46 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth" 47 authclient "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/client/utils" 48 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/exported" 49 authtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/types" 50 abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types" 51 "github.com/fibonacci-chain/fbc/libs/tendermint/crypto/merkle" 52 "github.com/fibonacci-chain/fbc/libs/tendermint/global" 53 "github.com/fibonacci-chain/fbc/libs/tendermint/libs/log" 54 tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types" 55 "github.com/fibonacci-chain/fbc/x/evm" 56 evmtypes "github.com/fibonacci-chain/fbc/x/evm/types" 57 "github.com/fibonacci-chain/fbc/x/evm/watcher" 58 ) 59 60 const ( 61 CacheOfEthCallLru = 40960 62 63 FlagFastQueryThreshold = "fast-query-threshold" 64 65 NameSpace = "eth" 66 67 EvmHookGasEstimate = uint64(60000) 68 EvmDefaultGasLimit = uint64(21000) 69 70 FlagAllowUnprotectedTxs = "rpc.allow-unprotected-txs" 71 ) 72 73 // PublicEthereumAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec. 74 type PublicEthereumAPI struct { 75 ctx context.Context 76 clientCtx clientcontext.CLIContext 77 chainIDEpoch *big.Int 78 logger log.Logger 79 backend backend.Backend 80 keys []ethsecp256k1.PrivKey // unlocked keys 81 nonceLock *rpctypes.AddrLocker 82 keyringLock sync.Mutex 83 gasPrice *hexutil.Big 84 wrappedBackend *watcher.Querier 85 watcherBackend *watcher.Watcher 86 evmFactory simulation.EvmFactory 87 txPool *TxPool 88 Metrics *monitor.RpcMetrics 89 callCache *lru.Cache 90 cdc *codec.Codec 91 fastQueryThreshold uint64 92 } 93 94 // NewAPI creates an instance of the public ETH Web3 API. 95 func NewAPI( 96 clientCtx clientcontext.CLIContext, log log.Logger, backend backend.Backend, nonceLock *rpctypes.AddrLocker, 97 keys ...ethsecp256k1.PrivKey, 98 ) *PublicEthereumAPI { 99 100 epoch, err := ethermint.ParseChainID(clientCtx.ChainID) 101 if err != nil { 102 panic(err) 103 } 104 105 api := &PublicEthereumAPI{ 106 ctx: context.Background(), 107 clientCtx: clientCtx, 108 chainIDEpoch: epoch, 109 logger: log.With("module", "json-rpc", "namespace", NameSpace), 110 backend: backend, 111 keys: keys, 112 nonceLock: nonceLock, 113 gasPrice: ParseGasPrice(), 114 wrappedBackend: watcher.NewQuerier(), 115 watcherBackend: watcher.NewWatcher(log), 116 fastQueryThreshold: viper.GetUint64(FlagFastQueryThreshold), 117 } 118 api.evmFactory = simulation.NewEvmFactory(clientCtx.ChainID, api.wrappedBackend) 119 module := evm.AppModuleBasic{} 120 api.cdc = codec.New() 121 module.RegisterCodec(api.cdc) 122 if watcher.IsWatcherEnabled() { 123 callCache, err := lru.New(CacheOfEthCallLru) 124 if err != nil { 125 panic(err) 126 } 127 api.callCache = callCache 128 } 129 130 if err := api.GetKeyringInfo(); err != nil { 131 api.logger.Error("failed to get keybase info", "error", err) 132 } 133 134 if viper.GetBool(FlagEnableTxPool) { 135 api.txPool = NewTxPool(clientCtx, api) 136 go api.txPool.broadcastPeriod(api) 137 } 138 139 if viper.GetBool(monitor.FlagEnableMonitor) { 140 api.Metrics = monitor.MakeMonitorMetrics(NameSpace) 141 } 142 return api 143 } 144 145 // GetKeyringInfo checks if the keyring is present on the client context. If not, it creates a new 146 // instance and sets it to the client context for later usage. 147 func (api *PublicEthereumAPI) GetKeyringInfo() error { 148 api.keyringLock.Lock() 149 defer api.keyringLock.Unlock() 150 151 if api.clientCtx.Keybase != nil { 152 return nil 153 } 154 backendType := viper.GetString(flags.FlagKeyringBackend) 155 if backendType == keys.BackendFile { 156 backendType = keys.BackendFileForRPC 157 } 158 keybase, err := keys.NewKeyring( 159 sdk.KeyringServiceName(), 160 backendType, 161 viper.GetString(cmserver.FlagUlockKeyHome), 162 api.clientCtx.Input, 163 hd.EthSecp256k1Options()..., 164 ) 165 if err != nil { 166 return err 167 } 168 169 api.clientCtx.Keybase = keybase 170 return nil 171 } 172 173 // ClientCtx returns the Cosmos SDK client context. 174 func (api *PublicEthereumAPI) ClientCtx() clientcontext.CLIContext { 175 return api.clientCtx 176 } 177 178 func (api *PublicEthereumAPI) GetCodec() *codec.Codec { 179 return api.cdc 180 } 181 182 // GetKeys returns the Cosmos SDK client context. 183 func (api *PublicEthereumAPI) GetKeys() []ethsecp256k1.PrivKey { 184 return api.keys 185 } 186 187 // SetKeys sets the given key slice to the set of private keys 188 func (api *PublicEthereumAPI) SetKeys(keys []ethsecp256k1.PrivKey) { 189 api.keys = keys 190 } 191 192 // ProtocolVersion returns the supported Ethereum protocol version. 193 func (api *PublicEthereumAPI) ProtocolVersion() hexutil.Uint { 194 monitor := monitor.GetMonitor("eth_protocolVersion", api.logger, api.Metrics).OnBegin() 195 defer monitor.OnEnd() 196 return hexutil.Uint(ethermint.ProtocolVersion) 197 } 198 199 // ChainId returns the chain's identifier in hex format 200 func (api *PublicEthereumAPI) ChainId() (hexutil.Uint, error) { // nolint 201 api.logger.Debug("eth_chainId") 202 203 height := global.GetGlobalHeight() 204 networkId := api.clientCtx.ChainID 205 206 if tmtypes.HigherThanJupiter(height) { 207 if types.IsMainNetChainID(networkId) { 208 chainID := big.NewInt(types.JupiterMainNetChainId) 209 return hexutil.Uint(uint(chainID.Uint64())), nil 210 } else if types.IsTestNetChainID(networkId) { 211 chainID := big.NewInt(types.JupiterTestNetChainId) 212 return hexutil.Uint(uint(chainID.Uint64())), nil 213 } 214 } 215 216 return hexutil.Uint(uint(api.chainIDEpoch.Uint64())), nil 217 } 218 219 // Syncing returns whether or not the current node is syncing with other peers. Returns false if not, or a struct 220 // outlining the state of the sync if it is. 221 func (api *PublicEthereumAPI) Syncing() (interface{}, error) { 222 monitor := monitor.GetMonitor("eth_syncing", api.logger, api.Metrics).OnBegin() 223 defer monitor.OnEnd() 224 status, err := api.clientCtx.Client.Status() 225 if err != nil { 226 return false, err 227 } 228 229 if !status.SyncInfo.CatchingUp { 230 return false, nil 231 } 232 233 return map[string]interface{}{ 234 "startingBlock": hexutil.Uint64(status.SyncInfo.EarliestBlockHeight), 235 "currentBlock": hexutil.Uint64(status.SyncInfo.LatestBlockHeight), 236 "highestBlock": hexutil.Uint64(0), // NA 237 // "pulledStates": nil, // NA 238 // "knownStates": nil, // NA 239 }, nil 240 } 241 242 // Coinbase is the address that staking rewards will be send to (alias for Etherbase). 243 func (api *PublicEthereumAPI) Coinbase() (common.Address, error) { 244 api.logger.Debug("eth_coinbase") 245 246 node, err := api.clientCtx.GetNode() 247 if err != nil { 248 return common.Address{}, err 249 } 250 251 status, err := node.Status() 252 if err != nil { 253 return common.Address{}, err 254 } 255 256 return common.BytesToAddress(status.ValidatorInfo.Address.Bytes()), nil 257 } 258 259 // Mining returns whether or not this node is currently mining. Always false. 260 func (api *PublicEthereumAPI) Mining() bool { 261 api.logger.Debug("eth_mining") 262 return false 263 } 264 265 // Hashrate returns the current node's hashrate. Always 0. 266 func (api *PublicEthereumAPI) Hashrate() hexutil.Uint64 { 267 api.logger.Debug("eth_hashrate") 268 return 0 269 } 270 271 // GasPrice returns the current gas price based on Ethermint's gas price oracle. 272 func (api *PublicEthereumAPI) GasPrice() *hexutil.Big { 273 monitor := monitor.GetMonitor("eth_gasPrice", api.logger, api.Metrics).OnBegin() 274 defer monitor.OnEnd() 275 276 minGP := (*big.Int)(api.gasPrice) 277 maxGP := new(big.Int).Mul(minGP, big.NewInt(5000)) 278 279 rgp := new(big.Int).Set(minGP) 280 if appconfig.GetFecConfig().GetDynamicGpMode() != tmtypes.MinimalGpMode { 281 // If current block is not congested, rgp == minimal gas price. 282 if mempool.IsCongested { 283 rgp.Set(mempool.GlobalRecommendedGP) 284 } 285 286 if rgp.Cmp(minGP) == -1 { 287 rgp.Set(minGP) 288 } 289 290 if appconfig.GetFecConfig().GetDynamicGpCoefficient() > 1 { 291 coefficient := big.NewInt(int64(appconfig.GetFecConfig().GetDynamicGpCoefficient())) 292 rgp = new(big.Int).Mul(rgp, coefficient) 293 } 294 295 if rgp.Cmp(maxGP) == 1 { 296 rgp.Set(maxGP) 297 } 298 } 299 300 return (*hexutil.Big)(rgp) 301 } 302 303 func (api *PublicEthereumAPI) GasPriceIn3Gears() *rpctypes.GPIn3Gears { 304 monitor := monitor.GetMonitor("eth_gasPriceIn3Gears", api.logger, api.Metrics).OnBegin() 305 defer monitor.OnEnd() 306 307 minGP := (*big.Int)(api.gasPrice) 308 maxGP := new(big.Int).Mul(minGP, big.NewInt(5000)) 309 310 avgGP := new(big.Int).Set(minGP) 311 if appconfig.GetFecConfig().GetDynamicGpMode() != tmtypes.MinimalGpMode { 312 if mempool.IsCongested { 313 avgGP.Set(mempool.GlobalRecommendedGP) 314 } 315 316 if avgGP.Cmp(minGP) == -1 { 317 avgGP.Set(minGP) 318 } 319 320 if appconfig.GetFecConfig().GetDynamicGpCoefficient() > 1 { 321 coefficient := big.NewInt(int64(appconfig.GetFecConfig().GetDynamicGpCoefficient())) 322 avgGP = new(big.Int).Mul(avgGP, coefficient) 323 } 324 325 if avgGP.Cmp(maxGP) == 1 { 326 avgGP.Set(maxGP) 327 } 328 } 329 330 // safe low GP = average GP * 0.5, but it will not be less than the minimal GP. 331 safeGp := new(big.Int).Quo(avgGP, big.NewInt(2)) 332 if safeGp.Cmp(minGP) == -1 { 333 safeGp.Set(minGP) 334 } 335 // fastest GP = average GP * 1.5, but it will not be greater than the max GP. 336 fastestGp := new(big.Int).Add(avgGP, new(big.Int).Quo(avgGP, big.NewInt(2))) 337 if fastestGp.Cmp(maxGP) == 1 { 338 fastestGp.Set(maxGP) 339 } 340 341 res := rpctypes.NewGPIn3Gears(safeGp, avgGP, fastestGp) 342 return &res 343 } 344 345 // Accounts returns the list of accounts available to this node. 346 func (api *PublicEthereumAPI) Accounts() ([]common.Address, error) { 347 monitor := monitor.GetMonitor("eth_accounts", api.logger, api.Metrics).OnBegin() 348 defer monitor.OnEnd() 349 return api.accounts() 350 } 351 352 func (api *PublicEthereumAPI) accounts() ([]common.Address, error) { 353 api.keyringLock.Lock() 354 defer api.keyringLock.Unlock() 355 356 addresses := make([]common.Address, 0) // return [] instead of nil if empty 357 358 infos, err := api.clientCtx.Keybase.List() 359 if err != nil { 360 return addresses, err 361 } 362 363 for _, info := range infos { 364 addressBytes := info.GetPubKey().Address().Bytes() 365 addresses = append(addresses, common.BytesToAddress(addressBytes)) 366 } 367 368 return addresses, nil 369 } 370 371 // BlockNumber returns the current block number. 372 func (api *PublicEthereumAPI) BlockNumber() (hexutil.Uint64, error) { 373 monitor := monitor.GetMonitor("eth_blockNumber", api.logger, api.Metrics).OnBegin() 374 defer monitor.OnEnd() 375 return api.backend.BlockNumber() 376 } 377 378 // GetBalance returns the provided account's balance up to the provided block number. 379 func (api *PublicEthereumAPI) GetBalance(address common.Address, blockNrOrHash rpctypes.BlockNumberOrHash) (*hexutil.Big, error) { 380 monitor := monitor.GetMonitor("eth_getBalance", api.logger, api.Metrics).OnBegin() 381 defer monitor.OnEnd("address", address, "block number", blockNrOrHash) 382 blockNum, err := api.backend.ConvertToBlockNumber(blockNrOrHash) 383 if err != nil { 384 return nil, err 385 } 386 useWatchBackend := api.useWatchBackend(blockNum) 387 if useWatchBackend { 388 acc, err := api.wrappedBackend.MustGetAccount(address.Bytes()) 389 if err == nil { 390 balance := acc.GetCoins().AmountOf(sdk.DefaultBondDenom).BigInt() 391 if balance == nil { 392 return (*hexutil.Big)(sdk.ZeroInt().BigInt()), nil 393 } 394 return (*hexutil.Big)(balance), nil 395 } 396 } 397 398 clientCtx := api.clientCtx 399 if !(blockNum == rpctypes.PendingBlockNumber || blockNum == rpctypes.LatestBlockNumber) && !useWatchBackend { 400 clientCtx = api.clientCtx.WithHeight(blockNum.Int64()) 401 } 402 403 bs, err := api.clientCtx.Codec.MarshalJSON(auth.NewQueryAccountParams(address.Bytes())) 404 if err != nil { 405 return nil, err 406 } 407 408 res, _, err := clientCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", auth.QuerierRoute, auth.QueryAccount), bs) 409 if err != nil { 410 if isAccountNotExistErr(err) { 411 if useWatchBackend { 412 api.saveZeroAccount(address) 413 } 414 return (*hexutil.Big)(sdk.ZeroInt().BigInt()), nil 415 } 416 return nil, err 417 } 418 419 var account ethermint.EthAccount 420 if err := api.clientCtx.Codec.UnmarshalJSON(res, &account); err != nil { 421 return nil, err 422 } 423 424 val := account.Balance(sdk.DefaultBondDenom).BigInt() 425 if useWatchBackend { 426 api.watcherBackend.CommitAccountToRpcDb(account) 427 } 428 429 if blockNum != rpctypes.PendingBlockNumber { 430 return (*hexutil.Big)(val), nil 431 } 432 433 // update the address balance with the pending transactions value (if applicable) 434 pendingTxs, err := api.backend.UserPendingTransactions(address.String(), -1) 435 if err != nil { 436 return nil, err 437 } 438 439 for _, tx := range pendingTxs { 440 if tx == nil { 441 continue 442 } 443 444 if tx.From == address { 445 val = new(big.Int).Sub(val, tx.Value.ToInt()) 446 } 447 if *tx.To == address { 448 val = new(big.Int).Add(val, tx.Value.ToInt()) 449 } 450 } 451 452 return (*hexutil.Big)(val), nil 453 } 454 455 // GetAccount returns the provided account's balance up to the provided block number. 456 func (api *PublicEthereumAPI) GetAccount(address common.Address) (*ethermint.EthAccount, error) { 457 acc, err := api.wrappedBackend.MustGetAccount(address.Bytes()) 458 if err == nil { 459 return acc, nil 460 } 461 clientCtx := api.clientCtx 462 463 bs, err := api.clientCtx.Codec.MarshalJSON(auth.NewQueryAccountParams(address.Bytes())) 464 if err != nil { 465 return nil, err 466 } 467 468 res, _, err := clientCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", auth.QuerierRoute, auth.QueryAccount), bs) 469 if err != nil { 470 return nil, err 471 } 472 473 var account ethermint.EthAccount 474 if err := api.clientCtx.Codec.UnmarshalJSON(res, &account); err != nil { 475 return nil, err 476 } 477 478 api.watcherBackend.CommitAccountToRpcDb(account) 479 480 return &account, nil 481 } 482 483 func (api *PublicEthereumAPI) getStorageAt(address common.Address, key []byte, blockNum rpctypes.BlockNumber, directlyKey bool) (hexutil.Bytes, error) { 484 clientCtx := api.clientCtx.WithHeight(blockNum.Int64()) 485 useWatchBackend := api.useWatchBackend(blockNum) 486 487 qWatchdbKey := key 488 if useWatchBackend { 489 if !directlyKey { 490 qWatchdbKey = evmtypes.GetStorageByAddressKey(address.Bytes(), key).Bytes() 491 } 492 res, err := api.wrappedBackend.MustGetState(address, qWatchdbKey) 493 if err == nil { 494 return res, nil 495 } 496 } 497 498 var queryStr = "" 499 if !directlyKey { 500 queryStr = fmt.Sprintf("custom/%s/storage/%s/%X", evmtypes.ModuleName, address.Hex(), key) 501 } else { 502 queryStr = fmt.Sprintf("custom/%s/storageKey/%s/%X", evmtypes.ModuleName, address.Hex(), key) 503 } 504 505 res, _, err := clientCtx.QueryWithData(queryStr, nil) 506 if err != nil { 507 return nil, err 508 } 509 510 var out evmtypes.QueryResStorage 511 api.clientCtx.Codec.MustUnmarshalJSON(res, &out) 512 if useWatchBackend { 513 api.watcherBackend.CommitStateToRpcDb(address, qWatchdbKey, out.Value) 514 } 515 return out.Value, nil 516 } 517 518 // GetStorageAt returns the contract storage at the given address, block number, and key. 519 func (api *PublicEthereumAPI) GetStorageAt(address common.Address, key string, blockNrOrHash rpctypes.BlockNumberOrHash) (hexutil.Bytes, error) { 520 monitor := monitor.GetMonitor("eth_getStorageAt", api.logger, api.Metrics).OnBegin() 521 defer monitor.OnEnd("address", address, "key", key, "block number", blockNrOrHash) 522 blockNum, err := api.backend.ConvertToBlockNumber(blockNrOrHash) 523 if err != nil { 524 return nil, err 525 } 526 return api.getStorageAt(address, common.HexToHash(key).Bytes(), blockNum, false) 527 } 528 529 // GetStorageAtInternal returns the contract storage at the given address, block number, and key. 530 func (api *PublicEthereumAPI) GetStorageAtInternal(address common.Address, key []byte) (hexutil.Bytes, error) { 531 return api.getStorageAt(address, key, 0, true) 532 } 533 534 // GetTransactionCount returns the number of transactions at the given address up to the given block number. 535 func (api *PublicEthereumAPI) GetTransactionCount(address common.Address, blockNrOrHash rpctypes.BlockNumberOrHash) (*hexutil.Uint64, error) { 536 monitor := monitor.GetMonitor("eth_getTransactionCount", api.logger, api.Metrics).OnBegin() 537 defer monitor.OnEnd("address", address, "block number", blockNrOrHash) 538 539 blockNum, err := api.backend.ConvertToBlockNumber(blockNrOrHash) 540 if err != nil { 541 return nil, err 542 } 543 544 // do not support block number param when node is pruning everything 545 if api.backend.PruneEverything() && blockNum != rpctypes.PendingBlockNumber { 546 blockNum = rpctypes.LatestBlockNumber 547 } 548 549 clientCtx := api.clientCtx 550 pending := blockNum == rpctypes.PendingBlockNumber 551 // pass the given block height to the context if the height is not pending or latest 552 if !pending && blockNum != rpctypes.LatestBlockNumber { 553 clientCtx = api.clientCtx.WithHeight(blockNum.Int64()) 554 } 555 useWatchBackend := api.useWatchBackend(blockNum) 556 nonce, err := api.accountNonce(clientCtx, address, pending, useWatchBackend) 557 if err != nil { 558 return nil, err 559 } 560 561 n := hexutil.Uint64(nonce) 562 return &n, nil 563 } 564 565 // GetBlockTransactionCountByHash returns the number of transactions in the block identified by hash. 566 func (api *PublicEthereumAPI) GetBlockTransactionCountByHash(hash common.Hash) *hexutil.Uint { 567 monitor := monitor.GetMonitor("eth_getBlockTransactionCountByHash", api.logger, api.Metrics).OnBegin() 568 defer monitor.OnEnd("hash", hash) 569 res, _, err := api.clientCtx.Query(fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryHashToHeight, hash.Hex())) 570 if err != nil { 571 return nil 572 } 573 574 var out evmtypes.QueryResBlockNumber 575 if err := api.clientCtx.Codec.UnmarshalJSON(res, &out); err != nil { 576 return nil 577 } 578 579 resBlock, err := api.backend.Block(&out.Number) 580 if err != nil { 581 return nil 582 } 583 584 n := hexutil.Uint(len(resBlock.Block.Txs)) 585 return &n 586 } 587 588 // GetBlockTransactionCountByNumber returns the number of transactions in the block identified by its height. 589 func (api *PublicEthereumAPI) GetBlockTransactionCountByNumber(blockNum rpctypes.BlockNumber) *hexutil.Uint { 590 monitor := monitor.GetMonitor("eth_getBlockTransactionCountByNumber", api.logger, api.Metrics).OnBegin() 591 defer monitor.OnEnd("block number", blockNum) 592 var ( 593 height int64 594 err error 595 txCount hexutil.Uint 596 txs int 597 ) 598 599 switch blockNum { 600 case rpctypes.PendingBlockNumber: 601 height, err = api.backend.LatestBlockNumber() 602 if err != nil { 603 return nil 604 } 605 resBlock, err := api.backend.Block(&height) 606 if err != nil { 607 return nil 608 } 609 // get the pending transaction count 610 pendingCnt, err := api.backend.PendingTransactionCnt() 611 if err != nil { 612 return nil 613 } 614 txs = len(resBlock.Block.Txs) + pendingCnt 615 case rpctypes.LatestBlockNumber: 616 height, err = api.backend.LatestBlockNumber() 617 if err != nil { 618 return nil 619 } 620 resBlock, err := api.backend.Block(&height) 621 if err != nil { 622 return nil 623 } 624 txs = len(resBlock.Block.Txs) 625 default: 626 height = blockNum.Int64() 627 resBlock, err := api.backend.Block(&height) 628 if err != nil { 629 return nil 630 } 631 txs = len(resBlock.Block.Txs) 632 } 633 634 txCount = hexutil.Uint(txs) 635 return &txCount 636 } 637 638 // GetUncleCountByBlockHash returns the number of uncles in the block idenfied by hash. Always zero. 639 func (api *PublicEthereumAPI) GetUncleCountByBlockHash(_ common.Hash) hexutil.Uint { 640 return 0 641 } 642 643 // GetUncleCountByBlockNumber returns the number of uncles in the block idenfied by number. Always zero. 644 func (api *PublicEthereumAPI) GetUncleCountByBlockNumber(_ rpctypes.BlockNumber) hexutil.Uint { 645 return 0 646 } 647 648 // GetCode returns the contract code at the given address and block number. 649 func (api *PublicEthereumAPI) GetCode(address common.Address, blockNrOrHash rpctypes.BlockNumberOrHash) (hexutil.Bytes, error) { 650 monitor := monitor.GetMonitor("eth_getCode", api.logger, api.Metrics).OnBegin() 651 defer monitor.OnEnd("address", address, "block number", blockNrOrHash) 652 blockNumber, err := api.backend.ConvertToBlockNumber(blockNrOrHash) 653 if err != nil { 654 return nil, err 655 } 656 657 code, err := api.wrappedBackend.GetCode(address, uint64(blockNumber)) 658 if err == nil { 659 return code, nil 660 } 661 662 clientCtx := api.clientCtx 663 if !(blockNumber == rpctypes.PendingBlockNumber || blockNumber == rpctypes.LatestBlockNumber) { 664 clientCtx = api.clientCtx.WithHeight(blockNumber.Int64()) 665 } 666 res, _, err := clientCtx.QueryWithData(fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryCode, address.Hex()), nil) 667 if err != nil { 668 return nil, err 669 } 670 671 var out evmtypes.QueryResCode 672 api.clientCtx.Codec.MustUnmarshalJSON(res, &out) 673 return out.Code, nil 674 } 675 676 // GetCodeByHash returns the contract code at the given address and block number. 677 func (api *PublicEthereumAPI) GetCodeByHash(hash common.Hash) (hexutil.Bytes, error) { 678 code, err := api.wrappedBackend.GetCodeByHash(hash.Bytes()) 679 if err == nil { 680 return code, nil 681 } 682 clientCtx := api.clientCtx 683 res, _, err := clientCtx.QueryWithData(fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryCodeByHash, hash.Hex()), nil) 684 if err != nil { 685 return nil, err 686 } 687 688 var out evmtypes.QueryResCode 689 api.clientCtx.Codec.MustUnmarshalJSON(res, &out) 690 691 api.watcherBackend.CommitCodeHashToDb(hash.Bytes(), out.Code) 692 693 return out.Code, nil 694 } 695 696 // GetTransactionLogs returns the logs given a transaction hash. 697 func (api *PublicEthereumAPI) GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error) { 698 api.logger.Debug("eth_getTransactionLogs", "hash", txHash) 699 return api.backend.GetTransactionLogs(txHash) 700 } 701 702 // Sign signs the provided data using the private key of address via Geth's signature standard. 703 func (api *PublicEthereumAPI) Sign(address common.Address, data hexutil.Bytes) (hexutil.Bytes, error) { 704 monitor := monitor.GetMonitor("eth_sign", api.logger, api.Metrics).OnBegin() 705 defer monitor.OnEnd("address", address, "data", data) 706 // TODO: Change this functionality to find an unlocked account by address 707 key, exist := rpctypes.GetKeyByAddress(api.keys, address) 708 if !exist { 709 return nil, keystore.ErrLocked 710 } 711 712 // Sign the requested hash with the wallet 713 sig, err := crypto.Sign(accounts.TextHash(data), key.ToECDSA()) 714 if err != nil { 715 return nil, err 716 } 717 718 sig[crypto.RecoveryIDOffset] += 27 // transform V from 0/1 to 27/28 719 720 return sig, nil 721 } 722 723 // SendTransaction sends an Ethereum transaction. 724 func (api *PublicEthereumAPI) SendTransaction(args rpctypes.SendTxArgs) (common.Hash, error) { 725 monitor := monitor.GetMonitor("eth_sendTransaction", api.logger, api.Metrics).OnBegin() 726 defer monitor.OnEnd("args", args) 727 // TODO: Change this functionality to find an unlocked account by address 728 729 height, err := api.BlockNumber() 730 if err != nil { 731 return common.Hash{}, err 732 } 733 key, exist := rpctypes.GetKeyByAddress(api.keys, *args.From) 734 if !exist { 735 api.logger.Debug("failed to find key in keyring", "key", args.From) 736 return common.Hash{}, keystore.ErrLocked 737 } 738 739 // Mutex lock the address' nonce to avoid assigning it to multiple requests 740 if args.Nonce == nil { 741 api.nonceLock.LockAddr(*args.From) 742 defer api.nonceLock.UnlockAddr(*args.From) 743 } 744 745 // Assemble transaction from fields 746 tx, err := api.generateFromArgs(args) 747 if err != nil { 748 api.logger.Debug("failed to generate tx", "error", err) 749 return common.Hash{}, err 750 } 751 752 if err := tx.ValidateBasic(); err != nil { 753 api.logger.Debug("tx failed basic validation", "error", err) 754 return common.Hash{}, err 755 } 756 757 // Sign transaction 758 if err := tx.Sign(api.chainIDEpoch, key.ToECDSA()); err != nil { 759 api.logger.Debug("failed to sign tx", "error", err) 760 return common.Hash{}, err 761 } 762 763 var txEncoder sdk.TxEncoder 764 if tmtypes.HigherThanVenus(int64(height)) { 765 txEncoder = authclient.GetTxEncoder(nil, authclient.WithEthereumTx()) 766 } else { 767 txEncoder = authclient.GetTxEncoder(api.clientCtx.Codec) 768 } 769 770 // Encode transaction by RLP encoder 771 txBytes, err := txEncoder(tx) 772 if err != nil { 773 return common.Hash{}, err 774 } 775 776 // send chanData to txPool 777 if tmtypes.HigherThanVenus(int64(height)) && api.txPool != nil { 778 return broadcastTxByTxPool(api, tx, txBytes) 779 } 780 781 // Broadcast transaction in sync mode (default) 782 // NOTE: If error is encountered on the node, the broadcast will not return an error 783 res, err := api.clientCtx.BroadcastTx(txBytes) 784 if err != nil { 785 return common.Hash{}, err 786 } 787 788 if res.Code != abci.CodeTypeOK { 789 return CheckError(res) 790 } 791 792 // Return transaction hash 793 return common.HexToHash(res.TxHash), nil 794 } 795 796 // SendRawTransaction send a raw Ethereum transaction. 797 func (api *PublicEthereumAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) { 798 monitor := monitor.GetMonitor("eth_sendRawTransaction", api.logger, api.Metrics).OnBegin() 799 defer monitor.OnEnd("data", data) 800 height, err := api.BlockNumber() 801 if err != nil { 802 return common.Hash{}, err 803 } 804 txBytes := data 805 tx := new(evmtypes.MsgEthereumTx) 806 807 // RLP decode raw transaction bytes 808 if err := authtypes.EthereumTxDecode(data, tx); err != nil { 809 // Return nil is for when gasLimit overflows uint64 810 return common.Hash{}, err 811 } 812 813 if !tx.Protected() && !viper.GetBool(FlagAllowUnprotectedTxs) { 814 return common.Hash{}, errors.New("only replay-protected (EIP-155) transactions allowed over RPC") 815 } 816 817 if !tmtypes.HigherThanVenus(int64(height)) { 818 txBytes, err = authclient.GetTxEncoder(api.clientCtx.Codec)(tx) 819 if err != nil { 820 return common.Hash{}, err 821 } 822 } 823 824 // send chanData to txPool 825 if tmtypes.HigherThanVenus(int64(height)) && api.txPool != nil { 826 return broadcastTxByTxPool(api, tx, txBytes) 827 } 828 829 // TODO: Possibly log the contract creation address (if recipient address is nil) or tx data 830 // If error is encountered on the node, the broadcast will not return an error 831 res, err := api.clientCtx.BroadcastTx(txBytes) 832 if err != nil { 833 return common.Hash{}, err 834 } 835 836 if res.Code != abci.CodeTypeOK { 837 return CheckError(res) 838 } 839 // Return transaction hash 840 return common.HexToHash(res.TxHash), nil 841 } 842 843 func (api *PublicEthereumAPI) buildKey(args rpctypes.CallArgs) common.Hash { 844 latest, err := api.wrappedBackend.GetLatestBlockNumber() 845 if err != nil { 846 return common.Hash{} 847 } 848 return sha256.Sum256([]byte(args.String() + strconv.Itoa(int(latest)))) 849 } 850 851 func (api *PublicEthereumAPI) getFromCallCache(key common.Hash) ([]byte, bool) { 852 if api.callCache == nil { 853 return nil, false 854 } 855 nilKey := common.Hash{} 856 if key == nilKey { 857 return nil, false 858 } 859 cacheData, ok := api.callCache.Get(key) 860 if ok { 861 ret, ok := cacheData.([]byte) 862 if ok { 863 return ret, true 864 } 865 } 866 return nil, false 867 } 868 869 func (api *PublicEthereumAPI) addCallCache(key common.Hash, data []byte) { 870 if api.callCache == nil { 871 return 872 } 873 api.callCache.Add(key, data) 874 } 875 876 // Call performs a raw contract call. 877 func (api *PublicEthereumAPI) Call(args rpctypes.CallArgs, blockNrOrHash rpctypes.BlockNumberOrHash, overrides *evmtypes.StateOverrides) (hexutil.Bytes, error) { 878 monitor := monitor.GetMonitor("eth_call", api.logger, api.Metrics).OnBegin() 879 defer monitor.OnEnd("args", args, "block number", blockNrOrHash) 880 881 if overrides != nil { 882 if err := overrides.Check(); err != nil { 883 return nil, err 884 } 885 } 886 var key common.Hash 887 if overrides == nil { 888 key = api.buildKey(args) 889 if cacheData, ok := api.getFromCallCache(key); ok { 890 return cacheData, nil 891 } 892 } 893 894 blockNr, err := api.backend.ConvertToBlockNumber(blockNrOrHash) 895 if err != nil { 896 return nil, err 897 } 898 simRes, err := api.doCall(args, blockNr, big.NewInt(ethermint.DefaultRPCGasLimit), false, overrides) 899 if err != nil { 900 return []byte{}, TransformDataError(err, "eth_call") 901 } 902 903 data, err := evmtypes.DecodeResultData(simRes.Result.Data) 904 if err != nil { 905 return []byte{}, TransformDataError(err, "eth_call") 906 } 907 if overrides == nil { 908 api.addCallCache(key, data.Ret) 909 } 910 return data.Ret, nil 911 } 912 913 // DoCall performs a simulated call operation through the evmtypes. It returns the 914 // estimated gas used on the operation or an error if fails. 915 func (api *PublicEthereumAPI) doCall( 916 args rpctypes.CallArgs, 917 blockNum rpctypes.BlockNumber, 918 globalGasCap *big.Int, 919 isEstimate bool, 920 overrides *evmtypes.StateOverrides, 921 ) (*sdk.SimulationResponse, error) { 922 var err error 923 clientCtx := api.clientCtx 924 // pass the given block height to the context if the height is not pending or latest 925 if !(blockNum == rpctypes.PendingBlockNumber || blockNum == rpctypes.LatestBlockNumber) { 926 clientCtx = api.clientCtx.WithHeight(blockNum.Int64()) 927 } 928 929 // Set default gas & gas price if none were set 930 // Change this to uint64(math.MaxUint64 / 2) if gas cap can be configured 931 gas := uint64(ethermint.DefaultRPCGasLimit) 932 if args.Gas != nil { 933 gas = uint64(*args.Gas) 934 } 935 if globalGasCap != nil && globalGasCap.Uint64() < gas { 936 api.logger.Debug("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap) 937 gas = globalGasCap.Uint64() 938 } 939 940 // Set gas price using default or parameter if passed in 941 gasPrice := new(big.Int).SetUint64(ethermint.DefaultGasPrice) 942 if args.GasPrice != nil { 943 gasPrice = args.GasPrice.ToInt() 944 } 945 946 // Set value for transaction 947 value := new(big.Int) 948 if args.Value != nil { 949 value = args.Value.ToInt() 950 } 951 952 // Set Data if provided 953 var data []byte 954 if args.Data != nil { 955 data = []byte(*args.Data) 956 } 957 958 // Set sender address or use a default if none specified 959 var addr common.Address 960 if args.From != nil { 961 addr = *args.From 962 } 963 964 nonce := uint64(0) 965 if isEstimate && args.To == nil && args.Data != nil { 966 //only get real nonce when estimate gas and the action is contract deploy 967 nonce, _ = api.accountNonce(api.clientCtx, addr, true, true) 968 } 969 970 // Create new call message 971 msg := evmtypes.NewMsgEthereumTx(nonce, args.To, value, gas, gasPrice, data) 972 var overridesBytes []byte 973 if overrides != nil { 974 if overridesBytes, err = overrides.GetBytes(); err != nil { 975 return nil, fmt.Errorf("fail to encode overrides") 976 } 977 } 978 sim := api.evmFactory.BuildSimulator(api) 979 980 // evm tx to cm tx is no need watch db query 981 useWatch := api.useWatchBackend(blockNum) 982 if useWatch && args.To != nil && 983 api.JudgeEvm2CmTx(args.To.Bytes(), data) { 984 useWatch = false 985 } 986 987 //only worked when fast-query has been enabled 988 if sim != nil && useWatch { 989 return sim.DoCall(msg, addr.String(), overridesBytes, api.evmFactory.PutBackStorePool) 990 } 991 992 //Generate tx to be used to simulate (signature isn't needed) 993 var txEncoder sdk.TxEncoder 994 995 // get block height 996 height := global.GetGlobalHeight() 997 if tmtypes.HigherThanVenus(height) { 998 txEncoder = authclient.GetTxEncoder(nil, authclient.WithEthereumTx()) 999 } else { 1000 txEncoder = authclient.GetTxEncoder(clientCtx.Codec) 1001 } 1002 1003 // rlp encoder need pointer type, amino encoder will first dereference pointers. 1004 txBytes, err := txEncoder(msg) 1005 if err != nil { 1006 return nil, err 1007 } 1008 // Transaction simulation through query. only pass from when eth_estimateGas. 1009 // eth_call's from maybe nil 1010 var simulatePath string 1011 var queryData []byte 1012 if overrides != nil { 1013 simulatePath = fmt.Sprintf("app/simulateWithOverrides/%s", addr.String()) 1014 queryOverridesData := sdk.SimulateData{ 1015 TxBytes: txBytes, 1016 OverridesBytes: overridesBytes, 1017 } 1018 queryData, err = json.Marshal(queryOverridesData) 1019 if err != nil { 1020 return nil, fmt.Errorf("fail to encode queryData for simulateWithOverrides") 1021 } 1022 1023 } else { 1024 simulatePath = fmt.Sprintf("app/simulate/%s", addr.String()) 1025 queryData = txBytes 1026 } 1027 1028 res, _, err := clientCtx.QueryWithData(simulatePath, queryData) 1029 if err != nil { 1030 return nil, err 1031 } 1032 1033 var simResponse sdk.SimulationResponse 1034 if err := clientCtx.Codec.UnmarshalBinaryBare(res, &simResponse); err != nil { 1035 return nil, err 1036 } 1037 1038 return &simResponse, nil 1039 } 1040 func (api *PublicEthereumAPI) simDoCall(args rpctypes.CallArgs, cap uint64) (uint64, error) { 1041 // Create a helper to check if a gas allowance results in an executable transaction 1042 executable := func(gas uint64) (*sdk.SimulationResponse, error) { 1043 if gas != 0 { 1044 args.Gas = (*hexutil.Uint64)(&gas) 1045 } 1046 return api.doCall(args, 0, big.NewInt(int64(cap)), true, nil) 1047 } 1048 1049 // get exact gas limit 1050 exactResponse, err := executable(0) 1051 if err != nil { 1052 return 0, err 1053 } 1054 1055 // return if gas is provided by args 1056 if args.Gas != nil { 1057 return exactResponse.GasUsed, nil 1058 } 1059 1060 // use exact gas to run verify again 1061 verifiedResponse, err := executable(exactResponse.GasInfo.GasUsed) 1062 if err == nil { 1063 return verifiedResponse.GasInfo.GasUsed, nil 1064 } 1065 1066 // 1067 // Execute the binary search and hone in on an executable gas limit 1068 lo := exactResponse.GasInfo.GasUsed 1069 hi := cap 1070 for lo+1 < hi { 1071 mid := (hi + lo) / 2 1072 _, err := executable(mid) 1073 1074 // If the error is not nil(consensus error), it means the provided message 1075 // call or transaction will never be accepted no matter how much gas it is 1076 // assigned. Return the error directly, don't struggle any more. 1077 if err != nil { 1078 lo = mid 1079 } else { 1080 hi = mid 1081 } 1082 } 1083 1084 return hi, nil 1085 } 1086 1087 // EstimateGas returns an estimate of gas usage for the given smart contract call. 1088 func (api *PublicEthereumAPI) EstimateGas(args rpctypes.CallArgs) (hexutil.Uint64, error) { 1089 monitor := monitor.GetMonitor("eth_estimateGas", api.logger, api.Metrics).OnBegin() 1090 defer monitor.OnEnd("args", args) 1091 1092 params, err := api.getEvmParams() 1093 if err != nil { 1094 return 0, TransformDataError(err, "eth_estimateGas") 1095 } 1096 maxGasLimitPerTx := params.MaxGasLimitPerTx 1097 1098 if args.GasPrice == nil || args.GasPrice.ToInt().Sign() <= 0 { 1099 // set the default value for possible check of GasPrice 1100 args.GasPrice = api.gasPrice 1101 } 1102 1103 estimatedGas, err := api.simDoCall(args, maxGasLimitPerTx) 1104 if err != nil { 1105 return 0, TransformDataError(err, "eth_estimateGas") 1106 } 1107 1108 if estimatedGas > maxGasLimitPerTx { 1109 errMsg := fmt.Sprintf("estimate gas %v greater than system max gas limit per tx %v", estimatedGas, maxGasLimitPerTx) 1110 return 0, TransformDataError(sdk.ErrOutOfGas(errMsg), "eth_estimateGas") 1111 } 1112 1113 // The gasLimit of evm ordinary tx is 21000 by default. 1114 // Using gasBuffer will cause the gasLimit in MetaMask to be too large, which will affect the user experience. 1115 // Therefore, if an ordinary tx is received, just return the default gasLimit of evm. 1116 if estimatedGas == EvmDefaultGasLimit && args.Data == nil { 1117 return hexutil.Uint64(estimatedGas), nil 1118 } 1119 1120 gasBuffer := estimatedGas / 100 * config.GetFecConfig().GetGasLimitBuffer() 1121 //EvmHookGasEstimate: evm tx with cosmos hook,we cannot estimate hook gas 1122 //simple add EvmHookGasEstimate,run tx will refund the extra gas 1123 gas := estimatedGas + gasBuffer + EvmHookGasEstimate 1124 if gas > maxGasLimitPerTx { 1125 gas = maxGasLimitPerTx 1126 } 1127 1128 return hexutil.Uint64(gas), nil 1129 } 1130 1131 // GetBlockByHash returns the block identified by hash. 1132 func (api *PublicEthereumAPI) GetBlockByHash(hash common.Hash, fullTx bool) (*watcher.Block, error) { 1133 monitor := monitor.GetMonitor("eth_getBlockByHash", api.logger, api.Metrics).OnBegin() 1134 defer monitor.OnEnd("hash", hash, "full", fullTx) 1135 blockRes, err := api.backend.GetBlockByHash(hash, fullTx) 1136 if err != nil { 1137 return nil, TransformDataError(err, RPCEthGetBlockByHash) 1138 } 1139 return blockRes, err 1140 } 1141 1142 func (api *PublicEthereumAPI) getBlockByNumber(blockNum rpctypes.BlockNumber, fullTx bool) (blockRes *watcher.Block, err error) { 1143 if blockNum != rpctypes.PendingBlockNumber { 1144 blockRes, err = api.backend.GetBlockByNumber(blockNum, fullTx) 1145 return 1146 } 1147 1148 height, err := api.backend.LatestBlockNumber() 1149 if err != nil { 1150 return nil, err 1151 } 1152 1153 // latest block info 1154 latestBlock, err := api.backend.Block(&height) 1155 if err != nil { 1156 return nil, err 1157 } 1158 1159 // number of pending txs queried from the mempool 1160 unconfirmedTxs, err := api.clientCtx.Client.UnconfirmedTxs(1000) 1161 if err != nil { 1162 return nil, err 1163 } 1164 1165 gasUsed, ethTxs, err := rpctypes.EthTransactionsFromTendermint(api.clientCtx, unconfirmedTxs.Txs, common.BytesToHash(latestBlock.Block.Hash()), uint64(height)) 1166 if err != nil { 1167 return nil, err 1168 } 1169 1170 return rpctypes.FormatBlock( 1171 tmtypes.Header{ 1172 Version: latestBlock.Block.Version, 1173 ChainID: api.clientCtx.ChainID, 1174 Height: height + 1, 1175 Time: time.Unix(0, 0), 1176 LastBlockID: latestBlock.Block.LastBlockID, 1177 ValidatorsHash: latestBlock.Block.NextValidatorsHash, 1178 ProposerAddress: latestBlock.Block.ProposerAddress, 1179 }, 1180 0, 1181 latestBlock.Block.Hash(), 1182 0, 1183 gasUsed, 1184 ethTxs, 1185 ethtypes.Bloom{}, 1186 fullTx, 1187 ), nil 1188 } 1189 1190 // GetBlockByNumber returns the block identified by number. 1191 func (api *PublicEthereumAPI) GetBlockByNumber(blockNum rpctypes.BlockNumber, fullTx bool) (*watcher.Block, error) { 1192 monitor := monitor.GetMonitor("eth_getBlockByNumber", api.logger, api.Metrics).OnBegin() 1193 defer monitor.OnEnd("number", blockNum, "full", fullTx) 1194 1195 blockRes, err := api.getBlockByNumber(blockNum, fullTx) 1196 return blockRes, err 1197 } 1198 1199 // GetTransactionByHash returns the transaction identified by hash. 1200 func (api *PublicEthereumAPI) GetTransactionByHash(hash common.Hash) (*watcher.Transaction, error) { 1201 monitor := monitor.GetMonitor("eth_getTransactionByHash", api.logger, api.Metrics).OnBegin() 1202 defer monitor.OnEnd("hash", hash) 1203 tx, err := api.backend.GetTransactionByHash(hash) 1204 if err == nil { 1205 return tx, nil 1206 } 1207 // check if the tx is on the mempool 1208 pendingTx, pendingErr := api.PendingTransactionsByHash(hash) 1209 if pendingErr != nil { 1210 //to keep consistent with rpc of ethereum, should be return nil 1211 return nil, nil 1212 } 1213 return pendingTx, nil 1214 } 1215 1216 // GetTransactionByBlockHashAndIndex returns the transaction identified by hash and index. 1217 func (api *PublicEthereumAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*watcher.Transaction, error) { 1218 monitor := monitor.GetMonitor("eth_getTransactionByBlockHashAndIndex", api.logger, api.Metrics).OnBegin() 1219 defer monitor.OnEnd("hash", hash, "index", idx) 1220 res, _, err := api.clientCtx.Query(fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryHashToHeight, hash.Hex())) 1221 if err != nil { 1222 return nil, nil 1223 } 1224 1225 var out evmtypes.QueryResBlockNumber 1226 api.clientCtx.Codec.MustUnmarshalJSON(res, &out) 1227 1228 resBlock, err := api.backend.Block(&out.Number) 1229 if err != nil { 1230 return nil, nil 1231 } 1232 1233 return api.getTransactionByBlockAndIndex(resBlock.Block, idx) 1234 } 1235 1236 // GetTransactionByBlockNumberAndIndex returns the transaction identified by number and index. 1237 func (api *PublicEthereumAPI) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockNumber, idx hexutil.Uint) (*watcher.Transaction, error) { 1238 monitor := monitor.GetMonitor("eth_getTransactionByBlockNumberAndIndex", api.logger, api.Metrics).OnBegin() 1239 defer monitor.OnEnd("blockNum", blockNum, "index", idx) 1240 tx, e := api.wrappedBackend.GetTransactionByBlockNumberAndIndex(uint64(blockNum), uint(idx)) 1241 if e == nil && tx != nil { 1242 return tx, nil 1243 } 1244 var ( 1245 height int64 1246 err error 1247 ) 1248 1249 switch blockNum { 1250 case rpctypes.PendingBlockNumber: 1251 // get all the EVM pending txs 1252 pendingTxs, err := api.backend.PendingTransactions() 1253 if err != nil { 1254 return nil, err 1255 } 1256 1257 // return if index out of bounds 1258 if uint64(idx) >= uint64(len(pendingTxs)) { 1259 return nil, nil 1260 } 1261 1262 // change back to pendingTxs[idx] once pending queue is fixed. 1263 return pendingTxs[int(idx)], nil 1264 1265 case rpctypes.LatestBlockNumber: 1266 height, err = api.backend.LatestBlockNumber() 1267 if err != nil { 1268 return nil, err 1269 } 1270 1271 default: 1272 height = blockNum.Int64() 1273 } 1274 1275 resBlock, err := api.backend.Block(&height) 1276 if err != nil { 1277 return nil, err 1278 } 1279 1280 return api.getTransactionByBlockAndIndex(resBlock.Block, idx) 1281 } 1282 1283 func (api *PublicEthereumAPI) getTransactionByBlockAndIndex(block *tmtypes.Block, idx hexutil.Uint) (*watcher.Transaction, error) { 1284 // return if index out of bounds 1285 if uint64(idx) >= uint64(len(block.Txs)) { 1286 return nil, nil 1287 } 1288 1289 ethTx, err := rpctypes.RawTxToEthTx(api.clientCtx, block.Txs[idx], block.Height) 1290 if err != nil { 1291 // return nil error if the transaction is not a MsgEthereumTx 1292 return nil, nil 1293 } 1294 1295 height := uint64(block.Height) 1296 txHash := common.BytesToHash(ethTx.Hash) 1297 blockHash := common.BytesToHash(block.Hash()) 1298 return watcher.NewTransaction(ethTx, txHash, blockHash, height, uint64(idx)) 1299 } 1300 1301 // GetTransactionReceipt returns the transaction receipt identified by hash. 1302 func (api *PublicEthereumAPI) GetTransactionReceipt(hash common.Hash) (*watcher.TransactionReceipt, error) { 1303 monitor := monitor.GetMonitor("eth_getTransactionReceipt", api.logger, api.Metrics).OnBegin() 1304 defer monitor.OnEnd("hash", hash) 1305 res, e := api.wrappedBackend.GetTransactionReceipt(hash) 1306 if e == nil { 1307 return res, nil 1308 } 1309 1310 tx, err := api.clientCtx.Client.Tx(hash.Bytes(), false) 1311 if err != nil { 1312 // Return nil for transaction when not found 1313 return nil, nil 1314 } 1315 1316 // Query block for consensus hash 1317 block, err := api.backend.Block(&tx.Height) 1318 if err != nil { 1319 return nil, err 1320 } 1321 1322 blockHash := common.BytesToHash(block.Block.Hash()) 1323 1324 // Convert tx bytes to eth transaction 1325 ethTx, err := rpctypes.RawTxToEthTx(api.clientCtx, tx.Tx, tx.Height) 1326 if err != nil { 1327 return nil, err 1328 } 1329 1330 err = ethTx.VerifySig(api.chainIDEpoch, tx.Height) 1331 if err != nil { 1332 return nil, err 1333 } 1334 1335 cumulativeGasUsed := uint64(tx.TxResult.GasUsed) 1336 if tx.Index != 0 { 1337 cumulativeGasUsed += rpctypes.GetBlockCumulativeGas(api.clientCtx.Codec, block.Block, int(tx.Index)) 1338 } 1339 1340 // Set status codes based on tx result 1341 var status hexutil.Uint64 1342 if tx.TxResult.IsOK() { 1343 status = hexutil.Uint64(1) 1344 } else { 1345 status = hexutil.Uint64(0) 1346 } 1347 1348 txData := tx.TxResult.GetData() 1349 1350 data, err := evmtypes.DecodeResultData(txData) 1351 if err != nil { 1352 status = 0 // transaction failed 1353 } 1354 1355 if len(data.Logs) == 0 || status == 0 { 1356 data.Logs = []*ethtypes.Log{} 1357 data.Bloom = ethtypes.BytesToBloom(make([]byte, 256)) 1358 } 1359 contractAddr := &data.ContractAddress 1360 if data.ContractAddress == common.HexToAddress("0x00000000000000000000") { 1361 contractAddr = nil 1362 } 1363 1364 // fix gasUsed when deliverTx ante handler check sequence invalid 1365 gasUsed := tx.TxResult.GasUsed 1366 if tx.TxResult.Code == sdkerrors.ErrInvalidSequence.ABCICode() { 1367 gasUsed = 0 1368 } 1369 1370 receipt := &watcher.TransactionReceipt{ 1371 Status: status, 1372 CumulativeGasUsed: hexutil.Uint64(cumulativeGasUsed), 1373 LogsBloom: data.Bloom, 1374 Logs: data.Logs, 1375 TransactionHash: hash.String(), 1376 ContractAddress: contractAddr, 1377 GasUsed: hexutil.Uint64(gasUsed), 1378 BlockHash: blockHash.String(), 1379 BlockNumber: hexutil.Uint64(tx.Height), 1380 TransactionIndex: hexutil.Uint64(tx.Index), 1381 From: ethTx.GetFrom(), 1382 To: ethTx.To(), 1383 } 1384 1385 return receipt, nil 1386 } 1387 1388 // PendingTransactions returns the transactions that are in the transaction pool 1389 // and have a from address that is one of the accounts this node manages. 1390 func (api *PublicEthereumAPI) PendingTransactions() ([]*watcher.Transaction, error) { 1391 api.logger.Debug("eth_pendingTransactions") 1392 return api.backend.PendingTransactions() 1393 } 1394 1395 func (api *PublicEthereumAPI) PendingTransactionsByHash(target common.Hash) (*watcher.Transaction, error) { 1396 api.logger.Debug("eth_pendingTransactionsByHash") 1397 return api.backend.PendingTransactionsByHash(target) 1398 } 1399 1400 // GetUncleByBlockHashAndIndex returns the uncle identified by hash and index. Always returns nil. 1401 func (api *PublicEthereumAPI) GetUncleByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) map[string]interface{} { 1402 return nil 1403 } 1404 1405 // GetUncleByBlockNumberAndIndex returns the uncle identified by number and index. Always returns nil. 1406 func (api *PublicEthereumAPI) GetUncleByBlockNumberAndIndex(number hexutil.Uint, idx hexutil.Uint) map[string]interface{} { 1407 return nil 1408 } 1409 1410 // GetProof returns an account object with proof and any storage proofs 1411 func (api *PublicEthereumAPI) GetProof(address common.Address, storageKeys []string, blockNrOrHash rpctypes.BlockNumberOrHash) (*rpctypes.AccountResult, error) { 1412 monitor := monitor.GetMonitor("eth_getProof", api.logger, api.Metrics).OnBegin() 1413 defer monitor.OnEnd("address", address, "keys", storageKeys, "number", blockNrOrHash) 1414 blockNum, err := api.backend.ConvertToBlockNumber(blockNrOrHash) 1415 if err != nil { 1416 return nil, err 1417 } 1418 if blockNum == rpctypes.LatestBlockNumber { 1419 n, err := api.BlockNumber() 1420 if err != nil { 1421 return nil, err 1422 } 1423 blockNum = rpctypes.BlockNumber(n) 1424 } 1425 1426 clientCtx := api.clientCtx.WithHeight(int64(blockNum)) 1427 path := fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryAccount, address.Hex()) 1428 1429 // query eth account at block height 1430 resBz, _, err := clientCtx.Query(path) 1431 if err != nil { 1432 return nil, err 1433 } 1434 var account *evmtypes.QueryResAccount 1435 clientCtx.Codec.MustUnmarshalJSON(resBz, &account) 1436 1437 // query eth proof storage after MarsHeight 1438 if tmtypes.HigherThanMars(int64(blockNum)) { 1439 return api.getStorageProofInMpt(address, storageKeys, int64(blockNum), account) 1440 } 1441 1442 /* 1443 * query cosmos proof before MarsHeight 1444 */ 1445 storageProofs := make([]rpctypes.StorageResult, len(storageKeys)) 1446 for i, k := range storageKeys { 1447 data := append(evmtypes.AddressStoragePrefix(address), getStorageByAddressKey(address, common.HexToHash(k).Bytes()).Bytes()...) 1448 // Get value for key 1449 req := abci.RequestQuery{ 1450 Path: fmt.Sprintf("store/%s/key", evmtypes.StoreKey), 1451 Data: data, 1452 Height: int64(blockNum), 1453 Prove: true, 1454 } 1455 1456 vRes, err := clientCtx.QueryABCI(req) 1457 if err != nil { 1458 return nil, err 1459 } 1460 1461 var value evmtypes.QueryResStorage 1462 value.Value = vRes.GetValue() 1463 1464 // check for proof 1465 proof := vRes.GetProof() 1466 proofStr := new(merkle.Proof).String() 1467 if proof != nil { 1468 proofStr = proof.String() 1469 } 1470 1471 storageProofs[i] = rpctypes.StorageResult{ 1472 Key: k, 1473 Value: (*hexutil.Big)(common.BytesToHash(value.Value).Big()), 1474 Proof: []string{proofStr}, 1475 } 1476 } 1477 1478 req := abci.RequestQuery{ 1479 Path: fmt.Sprintf("store/%s/key", auth.StoreKey), 1480 Data: auth.AddressStoreKey(sdk.AccAddress(address.Bytes())), 1481 Height: int64(blockNum), 1482 Prove: true, 1483 } 1484 1485 res, err := clientCtx.QueryABCI(req) 1486 if err != nil { 1487 return nil, err 1488 } 1489 1490 // check for proof 1491 accountProof := res.GetProof() 1492 accProofStr := new(merkle.Proof).String() 1493 if accountProof != nil { 1494 accProofStr = accountProof.String() 1495 } 1496 1497 return &rpctypes.AccountResult{ 1498 Address: address, 1499 AccountProof: []string{accProofStr}, 1500 Balance: (*hexutil.Big)(utils.MustUnmarshalBigInt(account.Balance)), 1501 CodeHash: common.BytesToHash(account.CodeHash), 1502 Nonce: hexutil.Uint64(account.Nonce), 1503 StorageHash: common.Hash{}, // Ethermint doesn't have a storage hash 1504 StorageProof: storageProofs, 1505 }, nil 1506 } 1507 1508 func (api *PublicEthereumAPI) getStorageProofInMpt(address common.Address, storageKeys []string, blockNum int64, account *evmtypes.QueryResAccount) (*rpctypes.AccountResult, error) { 1509 clientCtx := api.clientCtx.WithHeight(blockNum) 1510 1511 // query storage proof 1512 storageProofs := make([]rpctypes.StorageResult, len(storageKeys)) 1513 for i, k := range storageKeys { 1514 queryStr := fmt.Sprintf("custom/%s/%s/%s/%X", evmtypes.ModuleName, evmtypes.QueryStorageProof, address.Hex(), common.HexToHash(k).Bytes()) 1515 res, _, err := clientCtx.QueryWithData(queryStr, nil) 1516 if err != nil { 1517 return nil, err 1518 } 1519 1520 var out evmtypes.QueryResStorageProof 1521 api.clientCtx.Codec.MustUnmarshalJSON(res, &out) 1522 1523 storageProofs[i] = rpctypes.StorageResult{ 1524 Key: k, 1525 Value: (*hexutil.Big)(common.BytesToHash(out.Value).Big()), 1526 Proof: toHexSlice(out.Proof), 1527 } 1528 } 1529 1530 // query account proof 1531 req := abci.RequestQuery{ 1532 Path: fmt.Sprintf("store/%s/key", mpt.StoreKey), 1533 Data: auth.AddressStoreKey(sdk.AccAddress(address.Bytes())), 1534 Height: int64(blockNum), 1535 Prove: true, 1536 } 1537 res, err := clientCtx.QueryABCI(req) 1538 if err != nil { 1539 return nil, err 1540 } 1541 var accProofList mpt.ProofList 1542 clientCtx.Codec.MustUnmarshalBinaryLengthPrefixed(res.GetProof().Ops[0].Data, &accProofList) 1543 1544 // query account storage Hash 1545 queryStr := fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryStorageRoot, address.Hex()) 1546 storageRootBytes, _, err := clientCtx.QueryWithData(queryStr, nil) 1547 if err != nil { 1548 return nil, err 1549 } 1550 1551 // return result 1552 return &rpctypes.AccountResult{ 1553 Address: address, 1554 AccountProof: toHexSlice(accProofList), 1555 Balance: (*hexutil.Big)(utils.MustUnmarshalBigInt(account.Balance)), 1556 CodeHash: common.BytesToHash(account.CodeHash), 1557 Nonce: hexutil.Uint64(account.Nonce), 1558 StorageHash: common.BytesToHash(storageRootBytes), 1559 StorageProof: storageProofs, 1560 }, nil 1561 } 1562 1563 // toHexSlice creates a slice of hex-strings based on []byte. 1564 func toHexSlice(b [][]byte) []string { 1565 r := make([]string, len(b)) 1566 for i := range b { 1567 r[i] = hexutil.Encode(b[i]) 1568 } 1569 return r 1570 } 1571 1572 // generateFromArgs populates tx message with args (used in RPC API) 1573 func (api *PublicEthereumAPI) generateFromArgs(args rpctypes.SendTxArgs) (*evmtypes.MsgEthereumTx, error) { 1574 var ( 1575 nonce, gasLimit uint64 1576 err error 1577 ) 1578 1579 amount := (*big.Int)(args.Value) 1580 gasPrice := (*big.Int)(args.GasPrice) 1581 1582 if args.GasPrice == nil { 1583 // Set default gas price 1584 // TODO: Change to min gas price from context once available through server/daemon 1585 gasPrice = api.gasPrice.ToInt() 1586 } 1587 1588 if args.Nonce != nil && (uint64)(*args.Nonce) > 0 { 1589 nonce = (uint64)(*args.Nonce) 1590 } else { 1591 // get the nonce from the account retriever and the pending transactions 1592 nonce, err = api.accountNonce(api.clientCtx, *args.From, true, true) 1593 if err != nil { 1594 return nil, err 1595 } 1596 } 1597 1598 if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) { 1599 return nil, errors.New("both 'data' and 'input' are set and not equal. Please use 'input' to pass transaction call data") 1600 } 1601 1602 // Sets input to either Input or Data, if both are set and not equal error above returns 1603 var input hexutil.Bytes 1604 if args.Input != nil { 1605 input = *args.Input 1606 } else if args.Data != nil { 1607 input = *args.Data 1608 } 1609 1610 if args.To == nil && len(input) == 0 { 1611 // Contract creation 1612 return nil, fmt.Errorf("contract creation without any data provided") 1613 } 1614 1615 if args.Gas == nil { 1616 callArgs := rpctypes.CallArgs{ 1617 From: args.From, 1618 To: args.To, 1619 Gas: args.Gas, 1620 GasPrice: args.GasPrice, 1621 Value: args.Value, 1622 Data: &input, 1623 } 1624 gl, err := api.EstimateGas(callArgs) 1625 if err != nil { 1626 return nil, err 1627 } 1628 gasLimit = uint64(gl) 1629 } else { 1630 gasLimit = (uint64)(*args.Gas) 1631 } 1632 msg := evmtypes.NewMsgEthereumTx(nonce, args.To, amount, gasLimit, gasPrice, input) 1633 1634 return msg, nil 1635 } 1636 1637 // pendingMsgs constructs an array of sdk.Msg. This method will check pending transactions and convert 1638 // those transactions into ethermint messages. 1639 func (api *PublicEthereumAPI) pendingMsgs() ([]sdk.Msg, error) { 1640 // nolint: prealloc 1641 var msgs []sdk.Msg 1642 1643 pendingTxs, err := api.PendingTransactions() 1644 if err != nil { 1645 return nil, err 1646 } 1647 1648 for _, pendingTx := range pendingTxs { 1649 // NOTE: we have to construct the EVM transaction instead of just casting from the tendermint 1650 // transactions because PendingTransactions only checks for MsgEthereumTx messages. 1651 1652 pendingGas, err := hexutil.DecodeUint64(pendingTx.Gas.String()) 1653 if err != nil { 1654 return nil, err 1655 } 1656 1657 pendingValue := pendingTx.Value.ToInt() 1658 pendingGasPrice := new(big.Int).SetUint64(ethermint.DefaultGasPrice) 1659 if pendingTx.GasPrice != nil { 1660 pendingGasPrice = pendingTx.GasPrice.ToInt() 1661 } 1662 1663 pendingData := pendingTx.Input 1664 nonce, _ := api.accountNonce(api.clientCtx, pendingTx.From, true, true) 1665 1666 msg := evmtypes.NewMsgEthereumTx(nonce, pendingTx.To, pendingValue, pendingGas, 1667 pendingGasPrice, pendingData) 1668 1669 msgs = append(msgs, msg) 1670 } 1671 1672 return msgs, nil 1673 } 1674 1675 // accountNonce returns looks up the transaction nonce count for a given address. If the pending boolean 1676 // is set to true, it will add to the counter all the uncommitted EVM transactions sent from the address. 1677 // NOTE: The function returns no error if the account doesn't exist. 1678 func (api *PublicEthereumAPI) accountNonce( 1679 clientCtx clientcontext.CLIContext, address common.Address, pending bool, useWatchBackend bool, 1680 ) (uint64, error) { 1681 if pending { 1682 // nonce is continuous in mempool txs 1683 pendingNonce, ok := api.backend.GetPendingNonce(address.String()) 1684 if ok { 1685 return pendingNonce + 1, nil 1686 } 1687 } 1688 1689 // Get nonce (sequence) of account from watch db 1690 if useWatchBackend { 1691 acc, err := api.wrappedBackend.MustGetAccount(address.Bytes()) 1692 if err == nil { 1693 return acc.GetSequence(), nil 1694 } 1695 } 1696 1697 // Get nonce (sequence) of account from chain db 1698 account, err := getAccountFromChain(clientCtx, address) 1699 if err != nil { 1700 if isAccountNotExistErr(err) { 1701 return 0, nil 1702 } 1703 return 0, err 1704 } 1705 if useWatchBackend { 1706 api.watcherBackend.CommitAccountToRpcDb(account) 1707 } 1708 return account.GetSequence(), nil 1709 } 1710 1711 func getAccountFromChain(clientCtx clientcontext.CLIContext, address common.Address) (exported.Account, error) { 1712 accRet := authtypes.NewAccountRetriever(clientCtx) 1713 from := sdk.AccAddress(address.Bytes()) 1714 return accRet.GetAccount(from) 1715 } 1716 1717 func (api *PublicEthereumAPI) saveZeroAccount(address common.Address) { 1718 zeroAccount := ethermint.EthAccount{BaseAccount: &auth.BaseAccount{}} 1719 zeroAccount.SetAddress(address.Bytes()) 1720 zeroAccount.SetBalance(sdk.DefaultBondDenom, sdk.ZeroDec()) 1721 api.watcherBackend.CommitAccountToRpcDb(zeroAccount) 1722 } 1723 1724 func (api *PublicEthereumAPI) FeeHistory(blockCount rpc.DecimalOrHex, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*rpctypes.FeeHistoryResult, error) { 1725 api.logger.Debug("eth_feeHistory") 1726 return nil, fmt.Errorf("unsupported rpc function: eth_FeeHistory") 1727 } 1728 1729 // FillTransaction fills the defaults (nonce, gas, gasPrice or 1559 fields) 1730 // on a given unsigned transaction, and returns it to the caller for further 1731 // processing (signing + broadcast). 1732 func (api *PublicEthereumAPI) FillTransaction(args rpctypes.SendTxArgs) (*rpctypes.SignTransactionResult, error) { 1733 1734 monitor := monitor.GetMonitor("eth_fillTransaction", api.logger, api.Metrics).OnBegin() 1735 defer monitor.OnEnd("args", args) 1736 1737 height, err := api.BlockNumber() 1738 if err != nil { 1739 return nil, err 1740 } 1741 1742 // Mutex lock the address' nonce to avoid assigning it to multiple requests 1743 if args.Nonce == nil { 1744 api.nonceLock.LockAddr(*args.From) 1745 defer api.nonceLock.UnlockAddr(*args.From) 1746 } 1747 1748 // Assemble transaction from fields 1749 tx, err := api.generateFromArgs(args) 1750 if err != nil { 1751 api.logger.Debug("failed to generate tx", "error", err) 1752 return nil, err 1753 } 1754 1755 if err := tx.ValidateBasic(); err != nil { 1756 api.logger.Debug("tx failed basic validation", "error", err) 1757 return nil, err 1758 } 1759 1760 var txEncoder sdk.TxEncoder 1761 if tmtypes.HigherThanVenus(int64(height)) { 1762 txEncoder = authclient.GetTxEncoder(nil, authclient.WithEthereumTx()) 1763 } else { 1764 txEncoder = authclient.GetTxEncoder(api.clientCtx.Codec) 1765 } 1766 1767 // Encode transaction by RLP encoder 1768 txBytes, err := txEncoder(tx) 1769 if err != nil { 1770 return nil, err 1771 } 1772 rpcTx := rpctypes.ToTransaction(tx, args.From) 1773 return &rpctypes.SignTransactionResult{ 1774 Raw: txBytes, 1775 Tx: rpcTx, 1776 }, nil 1777 } 1778 1779 func (api *PublicEthereumAPI) useWatchBackend(blockNum rpctypes.BlockNumber) bool { 1780 if !api.watcherBackend.Enabled() { 1781 return false 1782 } 1783 return blockNum == rpctypes.LatestBlockNumber || api.fastQueryThreshold <= 0 || global.GetGlobalHeight()-blockNum.Int64() <= int64(api.fastQueryThreshold) 1784 } 1785 1786 func (api *PublicEthereumAPI) getEvmParams() (*evmtypes.Params, error) { 1787 if api.watcherBackend.Enabled() { 1788 params, err := api.wrappedBackend.GetParams() 1789 if err == nil { 1790 return params, nil 1791 } 1792 } 1793 1794 paramsPath := fmt.Sprintf("custom/%s/%s", evmtypes.ModuleName, evmtypes.QueryParameters) 1795 res, _, err := api.clientCtx.QueryWithData(paramsPath, nil) 1796 var evmParams evmtypes.Params 1797 if err != nil { 1798 return nil, err 1799 } 1800 if err = api.clientCtx.Codec.UnmarshalJSON(res, &evmParams); err != nil { 1801 return nil, err 1802 } 1803 1804 return &evmParams, nil 1805 } 1806 1807 func (api *PublicEthereumAPI) JudgeEvm2CmTx(toAddr, payLoad []byte) bool { 1808 if !evm.IsMatchSystemContractFunction(payLoad) { 1809 return false 1810 } 1811 route := fmt.Sprintf("custom/%s/%s", evmtypes.ModuleName, evmtypes.QuerySysContractAddress) 1812 addr, _, err := api.clientCtx.QueryWithData(route, nil) 1813 if err == nil && len(addr) != 0 { 1814 return bytes.Equal(toAddr, addr) 1815 } 1816 return false 1817 }