rpc: support fetching pending nonce (#191)

* consider mempool tx when computing account nonce

* fix lint

* add condition on blocknbr

* add log

* update changelog
:

* cleanup
This commit is contained in:
Thomas Nguy 2021-06-30 16:30:01 +09:00 committed by GitHub
parent dcc9585595
commit 3b3daa4b48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 44 additions and 12 deletions

View File

@ -60,6 +60,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (evm) [tharsis#24](https://github.com/tharsis/ethermint/pull/24) Implement metrics for `MsgEthereumTx`, state transitions, `BeginBlock` and `EndBlock`. * (evm) [tharsis#24](https://github.com/tharsis/ethermint/pull/24) Implement metrics for `MsgEthereumTx`, state transitions, `BeginBlock` and `EndBlock`.
* (rpc) [#124](https://github.com/tharsis/ethermint/issues/124) Implement `txpool_content`, `txpool_inspect` and `txpool_status` RPC methods * (rpc) [#124](https://github.com/tharsis/ethermint/issues/124) Implement `txpool_content`, `txpool_inspect` and `txpool_status` RPC methods
* (rpc) [tharsis#112](https://github.com/tharsis/ethermint/pull/153) Fix `eth_coinbase` to return the ethereum address of the validator * (rpc) [tharsis#112](https://github.com/tharsis/ethermint/pull/153) Fix `eth_coinbase` to return the ethereum address of the validator
* (rpc) [tharsis#176](https://github.com/tharsis/ethermint/issues/176) Support fetching pending nonce
### Bug Fixes ### Bug Fixes

View File

@ -256,7 +256,8 @@ func (e *PublicAPI) GetTransactionCount(address common.Address, blockNum rpctype
return &n, nil return &n, nil
} }
_, nonce, err := accRet.GetAccountNumberSequence(e.clientCtx, from) includePending := blockNum == rpctypes.EthPendingBlockNumber
nonce, err := getAccountNonce(e.clientCtx, e.backend, address, includePending, e.logger)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -565,16 +566,12 @@ func (e *PublicAPI) doCall(
accessList = args.AccessList accessList = args.AccessList
} }
// Set destination address for call if args.From == nil {
var fromAddr sdk.AccAddress
if args.From != nil {
fromAddr = sdk.AccAddress(args.From.Bytes())
} else {
fromAddr = sdk.AccAddress(common.Address{}.Bytes())
args.From = &common.Address{} args.From = &common.Address{}
} }
_, seq, err := e.clientCtx.AccountRetriever.GetAccountNumberSequence(e.clientCtx, fromAddr) includePending := blockNr == rpctypes.EthPendingBlockNumber
seq, err := getAccountNonce(e.clientCtx, e.backend, *args.From, includePending, e.logger)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1018,9 +1015,6 @@ func (e *PublicAPI) GetProof(address common.Address, storageKeys []string, block
// provided on the args // provided on the args
func (e *PublicAPI) setTxDefaults(args rpctypes.SendTxArgs) (rpctypes.SendTxArgs, error) { func (e *PublicAPI) setTxDefaults(args rpctypes.SendTxArgs) (rpctypes.SendTxArgs, error) {
// Get nonce (sequence) from sender account
from := sdk.AccAddress(args.From.Bytes())
if args.GasPrice == nil { if args.GasPrice == nil {
// TODO: Change to either: // TODO: Change to either:
// - min gas price from context once available through server/daemon, or // - min gas price from context once available through server/daemon, or
@ -1031,7 +1025,7 @@ func (e *PublicAPI) setTxDefaults(args rpctypes.SendTxArgs) (rpctypes.SendTxArgs
if args.Nonce == nil { if args.Nonce == nil {
// get the nonce from the account retriever // get the nonce from the account retriever
// ignore error in case tge account doesn't exist yet // ignore error in case tge account doesn't exist yet
_, nonce, _ := e.clientCtx.AccountRetriever.GetAccountNumberSequence(e.clientCtx, from) nonce, _ := getAccountNonce(e.clientCtx, e.backend, args.From, true, e.logger)
args.Nonce = (*hexutil.Uint64)(&nonce) args.Nonce = (*hexutil.Uint64)(&nonce)
} }
@ -1084,3 +1078,40 @@ func (e *PublicAPI) setTxDefaults(args rpctypes.SendTxArgs) (rpctypes.SendTxArgs
return args, nil return args, nil
} }
// getAccountNonce returns the account nonce for the given account address.
// If the pending value is true, it will iterate over the mempool (pending)
// txs in order to compute and return the pending tx sequence.
// Todo: include the ability to specify a blockNumber
func getAccountNonce(ctx client.Context, backend backend.Backend, accAddr common.Address, pending bool, logger log.Logger) (uint64, error) {
_, nonce, err := ctx.AccountRetriever.GetAccountNumberSequence(ctx, accAddr.Bytes())
if err != nil {
return 0, err
}
if !pending {
return nonce, nil
}
// the account retriever doesn't include the uncommitted transactions on the nonce so we need to
// to manually add them.
pendingTxs, err := backend.PendingTransactions()
if err != nil {
logger.Errorln("fails to fetch pending transactions")
return nonce, nil
}
// add the uncommitted txs to the nonce counter
if len(pendingTxs) != 0 {
for i := range pendingTxs {
if pendingTxs[i] == nil {
continue
}
if pendingTxs[i].From == accAddr {
nonce++
}
}
}
return nonce, nil
}