forked from cerc-io/laconicd-deprecated
Pending (#571)
* add PendingBlockNumber -1 * increase block times * update bn * get pending balance * additional logic to check for pending state * add multiple balance query * pending state for getTransactionCount * fix lint * add getBlockTransactionCountByNumber code - commented * cleanup test * GetBlockTransactionCountByNumber * cleanup * getBlockByNumber * GetTransactionByBlockNumberAndIndex * conform to namespace changes * exportable FormatBlock method * eth_getTransactionByHash * eth_getTransactionByBlockNumberAndIndex * pending nonce * set nonce for pending and check for invalid * WIP: doCall * add pending tx test * cleanup + refactor * push first tests and init pending * pending changes (#600) * cleanup * updates * more fixes * lint * update call and send * comments and minor changes * add pending tests into sep package * fix latest case for eth_GetBlockTransactionCountByNumber * fix repeating null transactions in queue * remove repeated structs * latestblock case * revert init script back * fix to exportable method * automate pending tests; add make cmd * move and comment out pending call test * fix some golint * fix unlock issue * wip: linter stringer fix? * stringer lint * set arr instead of append * instantiate with length * sep if statement * edit pendingblocknumber note * switch statement * fix and update tests * move tests-pending into tests dir * remove commented test * revert to appending pendingtx * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * require no err * rename var * check result for eth_sendTransaction * update changelog * update * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update tests/tests-pending/rpc_pending_test.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * changelog * remove redundant check Co-authored-by: noot <elizabethjbinks@gmail.com> Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Federico Kunze <federico.kunze94@gmail.com>
This commit is contained in:
co-authored by
Federico Kunze
noot
Federico Kunze
parent
602e61adea
commit
cb96bc4ea3
+15
-6
@@ -22,6 +22,7 @@ import (
|
||||
type Backend interface {
|
||||
// Used by block filter; also used for polling
|
||||
BlockNumber() (hexutil.Uint64, error)
|
||||
LatestBlockNumber() (int64, error)
|
||||
HeaderByNumber(blockNum rpctypes.BlockNumber) (*ethtypes.Header, error)
|
||||
HeaderByHash(blockHash common.Hash) (*ethtypes.Header, error)
|
||||
GetBlockByNumber(blockNum rpctypes.BlockNumber, fullTx bool) (map[string]interface{}, error)
|
||||
@@ -60,13 +61,12 @@ func New(clientCtx clientcontext.CLIContext) *EthermintBackend {
|
||||
|
||||
// BlockNumber returns the current block number.
|
||||
func (b *EthermintBackend) BlockNumber() (hexutil.Uint64, error) {
|
||||
// NOTE: using 0 as min and max height returns the blockchain info up to the latest block.
|
||||
info, err := b.clientCtx.Client.BlockchainInfo(0, 0)
|
||||
blockNumber, err := b.LatestBlockNumber()
|
||||
if err != nil {
|
||||
return hexutil.Uint64(0), err
|
||||
}
|
||||
|
||||
return hexutil.Uint64(info.LastHeight), nil
|
||||
return hexutil.Uint64(blockNumber), nil
|
||||
}
|
||||
|
||||
// GetBlockByNumber returns the block identified by number.
|
||||
@@ -196,7 +196,7 @@ func (b *EthermintBackend) PendingTransactions() ([]*rpctypes.Transaction, error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
transactions := make([]*rpctypes.Transaction, pendingTxs.Count)
|
||||
transactions := make([]*rpctypes.Transaction, 0)
|
||||
for _, tx := range pendingTxs.Txs {
|
||||
ethTx, err := rpctypes.RawTxToEthTx(b.clientCtx, tx)
|
||||
if err != nil {
|
||||
@@ -209,10 +209,8 @@ func (b *EthermintBackend) PendingTransactions() ([]*rpctypes.Transaction, error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
transactions = append(transactions, rpcTx)
|
||||
}
|
||||
|
||||
return transactions, nil
|
||||
}
|
||||
|
||||
@@ -257,3 +255,14 @@ func (b *EthermintBackend) GetLogs(blockHash common.Hash) ([][]*ethtypes.Log, er
|
||||
func (b *EthermintBackend) BloomStatus() (uint64, uint64) {
|
||||
return 4096, 0
|
||||
}
|
||||
|
||||
// LatestBlockNumber gets the latest block height in int64 format.
|
||||
func (b *EthermintBackend) LatestBlockNumber() (int64, error) {
|
||||
// NOTE: using 0 as min and max height returns the blockchain info up to the latest block.
|
||||
info, err := b.clientCtx.Client.BlockchainInfo(0, 0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return info.LastHeight, nil
|
||||
}
|
||||
|
||||
+291
-47
@@ -8,6 +8,7 @@ import (
|
||||
"math/big"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
@@ -212,7 +213,7 @@ func (api *PublicEthereumAPI) Accounts() ([]common.Address, error) {
|
||||
return addresses, nil
|
||||
}
|
||||
|
||||
// rpctypes.BlockNumber returns the current block number.
|
||||
// BlockNumber returns the current block number.
|
||||
func (api *PublicEthereumAPI) BlockNumber() (hexutil.Uint64, error) {
|
||||
api.logger.Debug("eth_blockNumber")
|
||||
return api.backend.BlockNumber()
|
||||
@@ -221,7 +222,12 @@ func (api *PublicEthereumAPI) BlockNumber() (hexutil.Uint64, error) {
|
||||
// GetBalance returns the provided account's balance up to the provided block number.
|
||||
func (api *PublicEthereumAPI) GetBalance(address common.Address, blockNum rpctypes.BlockNumber) (*hexutil.Big, error) {
|
||||
api.logger.Debug("eth_getBalance", "address", address, "block number", blockNum)
|
||||
clientCtx := api.clientCtx.WithHeight(blockNum.Int64())
|
||||
|
||||
clientCtx := api.clientCtx
|
||||
if !(blockNum == rpctypes.PendingBlockNumber || blockNum == rpctypes.LatestBlockNumber) {
|
||||
clientCtx = api.clientCtx.WithHeight(blockNum.Int64())
|
||||
}
|
||||
|
||||
res, _, err := clientCtx.QueryWithData(fmt.Sprintf("custom/%s/balance/%s", evmtypes.ModuleName, address.Hex()), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -234,6 +240,29 @@ func (api *PublicEthereumAPI) GetBalance(address common.Address, blockNum rpctyp
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if blockNum != rpctypes.PendingBlockNumber {
|
||||
return (*hexutil.Big)(val), nil
|
||||
}
|
||||
|
||||
// update the address balance with the pending transactions value (if applicable)
|
||||
pendingTxs, err := api.backend.PendingTransactions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, tx := range pendingTxs {
|
||||
if tx == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if tx.From == address {
|
||||
val = new(big.Int).Sub(val, tx.Value.ToInt())
|
||||
}
|
||||
if *tx.To == address {
|
||||
val = new(big.Int).Add(val, tx.Value.ToInt())
|
||||
}
|
||||
}
|
||||
|
||||
return (*hexutil.Big)(val), nil
|
||||
}
|
||||
|
||||
@@ -254,20 +283,16 @@ func (api *PublicEthereumAPI) GetStorageAt(address common.Address, key string, b
|
||||
// GetTransactionCount returns the number of transactions at the given address up to the given block number.
|
||||
func (api *PublicEthereumAPI) GetTransactionCount(address common.Address, blockNum rpctypes.BlockNumber) (*hexutil.Uint64, error) {
|
||||
api.logger.Debug("eth_getTransactionCount", "address", address, "block number", blockNum)
|
||||
clientCtx := api.clientCtx.WithHeight(blockNum.Int64())
|
||||
|
||||
// Get nonce (sequence) from account
|
||||
from := sdk.AccAddress(address.Bytes())
|
||||
accRet := authtypes.NewAccountRetriever(clientCtx)
|
||||
clientCtx := api.clientCtx
|
||||
pending := blockNum == rpctypes.PendingBlockNumber
|
||||
|
||||
err := accRet.EnsureExists(from)
|
||||
if err != nil {
|
||||
// account doesn't exist yet, return 0
|
||||
n := hexutil.Uint64(0)
|
||||
return &n, nil
|
||||
// pass the given block height to the context if the height is not pending or latest
|
||||
if !pending && blockNum != rpctypes.LatestBlockNumber {
|
||||
clientCtx = api.clientCtx.WithHeight(blockNum.Int64())
|
||||
}
|
||||
|
||||
_, nonce, err := accRet.GetAccountNumberSequence(from)
|
||||
nonce, err := api.accountNonce(clientCtx, address, pending)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -298,17 +323,54 @@ func (api *PublicEthereumAPI) GetBlockTransactionCountByHash(hash common.Hash) *
|
||||
return &n
|
||||
}
|
||||
|
||||
// GetBlockTransactionCountByNumber returns the number of transactions in the block identified by number.
|
||||
// GetBlockTransactionCountByNumber returns the number of transactions in the block identified by its height.
|
||||
func (api *PublicEthereumAPI) GetBlockTransactionCountByNumber(blockNum rpctypes.BlockNumber) *hexutil.Uint {
|
||||
api.logger.Debug("eth_getBlockTransactionCountByNumber", "block number", blockNum)
|
||||
height := blockNum.Int64()
|
||||
resBlock, err := api.clientCtx.Client.Block(&height)
|
||||
if err != nil {
|
||||
return nil
|
||||
|
||||
var (
|
||||
height int64
|
||||
err error
|
||||
txCount hexutil.Uint
|
||||
txs int
|
||||
)
|
||||
|
||||
switch blockNum {
|
||||
case rpctypes.PendingBlockNumber:
|
||||
height, err = api.backend.LatestBlockNumber()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
resBlock, err := api.clientCtx.Client.Block(&height)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
// get the pending transaction count
|
||||
pendingTxs, err := api.backend.PendingTransactions()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
txs = len(resBlock.Block.Txs) + len(pendingTxs)
|
||||
case rpctypes.LatestBlockNumber:
|
||||
height, err = api.backend.LatestBlockNumber()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
resBlock, err := api.clientCtx.Client.Block(&height)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
txs = len(resBlock.Block.Txs)
|
||||
default:
|
||||
height = blockNum.Int64()
|
||||
resBlock, err := api.clientCtx.Client.Block(&height)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
txs = len(resBlock.Block.Txs)
|
||||
}
|
||||
|
||||
n := hexutil.Uint(len(resBlock.Block.Txs))
|
||||
return &n
|
||||
txCount = hexutil.Uint(txs)
|
||||
return &txCount
|
||||
}
|
||||
|
||||
// GetUncleCountByBlockHash returns the number of uncles in the block idenfied by hash. Always zero.
|
||||
@@ -385,6 +447,11 @@ func (api *PublicEthereumAPI) SendTransaction(args rpctypes.SendTxArgs) (common.
|
||||
return common.Hash{}, err
|
||||
}
|
||||
|
||||
if err := tx.ValidateBasic(); err != nil {
|
||||
api.logger.Debug("tx failed basic validation", "error", err)
|
||||
return common.Hash{}, err
|
||||
}
|
||||
|
||||
// Sign transaction
|
||||
if err := tx.Sign(api.chainIDEpoch, key.ToECDSA()); err != nil {
|
||||
api.logger.Debug("failed to sign tx", "error", err)
|
||||
@@ -457,13 +524,13 @@ func (api *PublicEthereumAPI) Call(args rpctypes.CallArgs, blockNr rpctypes.Bloc
|
||||
// DoCall performs a simulated call operation through the evmtypes. It returns the
|
||||
// estimated gas used on the operation or an error if fails.
|
||||
func (api *PublicEthereumAPI) doCall(
|
||||
args rpctypes.CallArgs, blockNr rpctypes.BlockNumber, globalGasCap *big.Int,
|
||||
args rpctypes.CallArgs, blockNum rpctypes.BlockNumber, globalGasCap *big.Int,
|
||||
) (*sdk.SimulationResponse, error) {
|
||||
// Set height for historical queries
|
||||
clientCtx := api.clientCtx
|
||||
|
||||
if blockNr.Int64() != 0 {
|
||||
clientCtx = api.clientCtx.WithHeight(blockNr.Int64())
|
||||
clientCtx := api.clientCtx
|
||||
// pass the given block height to the context if the height is not pending or latest
|
||||
if !(blockNum == rpctypes.PendingBlockNumber || blockNum == rpctypes.LatestBlockNumber) {
|
||||
clientCtx = api.clientCtx.WithHeight(blockNum.Int64())
|
||||
}
|
||||
|
||||
// Set sender address or use a default if none specified
|
||||
@@ -513,17 +580,29 @@ func (api *PublicEthereumAPI) doCall(
|
||||
toAddr = sdk.AccAddress(args.To.Bytes())
|
||||
}
|
||||
|
||||
var msgs []sdk.Msg
|
||||
// Create new call message
|
||||
msg := evmtypes.NewMsgEthermint(0, &toAddr, sdk.NewIntFromBigInt(value), gas,
|
||||
sdk.NewIntFromBigInt(gasPrice), data, sdk.AccAddress(addr.Bytes()))
|
||||
msgs = append(msgs, msg)
|
||||
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return nil, err
|
||||
// convert the pending transactions into ethermint msgs
|
||||
if blockNum == rpctypes.PendingBlockNumber {
|
||||
pendingMsgs, err := api.pendingMsgs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msgs = append(msgs, pendingMsgs...)
|
||||
}
|
||||
|
||||
// Generate tx to be used to simulate (signature isn't needed)
|
||||
var stdSig authtypes.StdSignature
|
||||
tx := authtypes.NewStdTx([]sdk.Msg{msg}, authtypes.StdFee{}, []authtypes.StdSignature{stdSig}, "")
|
||||
stdSigs := []authtypes.StdSignature{stdSig}
|
||||
|
||||
tx := authtypes.NewStdTx(msgs, authtypes.StdFee{}, stdSigs, "")
|
||||
if err := tx.ValidateBasic(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txEncoder := authclient.GetTxEncoder(clientCtx.Codec)
|
||||
txBytes, err := txEncoder(tx)
|
||||
@@ -571,14 +650,71 @@ func (api *PublicEthereumAPI) GetBlockByHash(hash common.Hash, fullTx bool) (map
|
||||
// GetBlockByNumber returns the block identified by number.
|
||||
func (api *PublicEthereumAPI) GetBlockByNumber(blockNum rpctypes.BlockNumber, fullTx bool) (map[string]interface{}, error) {
|
||||
api.logger.Debug("eth_getBlockByNumber", "number", blockNum, "full", fullTx)
|
||||
return api.backend.GetBlockByNumber(blockNum, fullTx)
|
||||
|
||||
if blockNum != rpctypes.PendingBlockNumber {
|
||||
return api.backend.GetBlockByNumber(blockNum, fullTx)
|
||||
}
|
||||
|
||||
height, err := api.backend.LatestBlockNumber()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// latest block info
|
||||
latestBlock, err := api.clientCtx.Client.Block(&height)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// number of pending txs queried from the mempool
|
||||
unconfirmedTxs, err := api.clientCtx.Client.UnconfirmedTxs(1000)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pendingTxs, gasUsed, err := rpctypes.EthTransactionsFromTendermint(api.clientCtx, unconfirmedTxs.Txs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rpctypes.FormatBlock(
|
||||
tmtypes.Header{
|
||||
Version: latestBlock.Block.Version,
|
||||
ChainID: api.clientCtx.ChainID,
|
||||
Height: height + 1,
|
||||
Time: time.Unix(0, 0),
|
||||
LastBlockID: latestBlock.BlockID,
|
||||
ValidatorsHash: latestBlock.Block.NextValidatorsHash,
|
||||
},
|
||||
0,
|
||||
0,
|
||||
gasUsed,
|
||||
pendingTxs,
|
||||
ethtypes.Bloom{},
|
||||
), nil
|
||||
|
||||
}
|
||||
|
||||
// GetTransactionByHash returns the transaction identified by hash.
|
||||
func (api *PublicEthereumAPI) GetTransactionByHash(hash common.Hash) (*rpctypes.Transaction, error) {
|
||||
api.logger.Debug("eth_getTransactionByHash", "hash", hash)
|
||||
|
||||
tx, err := api.clientCtx.Client.Tx(hash.Bytes(), false)
|
||||
if err != nil {
|
||||
// check if the tx is on the mempool
|
||||
pendingTxs, pendingErr := api.PendingTransactions()
|
||||
if pendingErr != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(pendingTxs) != 0 {
|
||||
for _, tx := range pendingTxs {
|
||||
if tx != nil && hash == tx.Hash {
|
||||
return tx, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return nil for transaction when not found
|
||||
return nil, nil
|
||||
}
|
||||
@@ -622,7 +758,37 @@ func (api *PublicEthereumAPI) GetTransactionByBlockHashAndIndex(hash common.Hash
|
||||
// GetTransactionByBlockNumberAndIndex returns the transaction identified by number and index.
|
||||
func (api *PublicEthereumAPI) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockNumber, idx hexutil.Uint) (*rpctypes.Transaction, error) {
|
||||
api.logger.Debug("eth_getTransactionByBlockNumberAndIndex", "number", blockNum, "index", idx)
|
||||
height := blockNum.Int64()
|
||||
var (
|
||||
height int64
|
||||
err error
|
||||
)
|
||||
|
||||
switch blockNum {
|
||||
case rpctypes.PendingBlockNumber:
|
||||
// get all the EVM pending txs
|
||||
pendingTxs, err := api.backend.PendingTransactions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// return if index out of bounds
|
||||
if uint64(idx) >= uint64(len(pendingTxs)) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// change back to pendingTxs[idx] once pending queue is fixed.
|
||||
return pendingTxs[int(idx)], nil
|
||||
|
||||
case rpctypes.LatestBlockNumber:
|
||||
height, err = api.backend.LatestBlockNumber()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
default:
|
||||
height = blockNum.Int64()
|
||||
}
|
||||
|
||||
resBlock, err := api.clientCtx.Client.Block(&height)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -731,7 +897,7 @@ func (api *PublicEthereumAPI) GetTransactionReceipt(hash common.Hash) (map[strin
|
||||
// PendingTransactions returns the transactions that are in the transaction pool
|
||||
// and have a from address that is one of the accounts this node manages.
|
||||
func (api *PublicEthereumAPI) PendingTransactions() ([]*rpctypes.Transaction, error) {
|
||||
api.logger.Debug("eth_getPendingTransactions")
|
||||
api.logger.Debug("eth_pendingTransactions")
|
||||
return api.backend.PendingTransactions()
|
||||
}
|
||||
|
||||
@@ -821,40 +987,32 @@ func (api *PublicEthereumAPI) GetProof(address common.Address, storageKeys []str
|
||||
// generateFromArgs populates tx message with args (used in RPC API)
|
||||
func (api *PublicEthereumAPI) generateFromArgs(args rpctypes.SendTxArgs) (*evmtypes.MsgEthereumTx, error) {
|
||||
var (
|
||||
nonce uint64
|
||||
gasLimit uint64
|
||||
err error
|
||||
nonce, gasLimit uint64
|
||||
err error
|
||||
)
|
||||
|
||||
amount := (*big.Int)(args.Value)
|
||||
gasPrice := (*big.Int)(args.GasPrice)
|
||||
|
||||
if args.GasPrice == nil {
|
||||
|
||||
// Set default gas price
|
||||
// TODO: Change to min gas price from context once available through server/daemon
|
||||
gasPrice = big.NewInt(ethermint.DefaultGasPrice)
|
||||
}
|
||||
|
||||
if args.Nonce == nil {
|
||||
// Get nonce (sequence) from account
|
||||
from := sdk.AccAddress(args.From.Bytes())
|
||||
accRet := authtypes.NewAccountRetriever(api.clientCtx)
|
||||
|
||||
if api.clientCtx.Keybase == nil {
|
||||
return nil, fmt.Errorf("clientCtx.Keybase is nil")
|
||||
}
|
||||
|
||||
_, nonce, err = accRet.GetAccountNumberSequence(from)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// get the nonce from the account retriever and the pending transactions
|
||||
nonce, err = api.accountNonce(api.clientCtx, args.From, true)
|
||||
} else {
|
||||
nonce = (uint64)(*args.Nonce)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) {
|
||||
return nil, errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`)
|
||||
return nil, errors.New("both 'data' and 'input' are set and not equal. Please use 'input' to pass transaction call data")
|
||||
}
|
||||
|
||||
// Sets input to either Input or Data, if both are set and not equal error above returns
|
||||
@@ -891,3 +1049,89 @@ func (api *PublicEthereumAPI) generateFromArgs(args rpctypes.SendTxArgs) (*evmty
|
||||
|
||||
return &msg, nil
|
||||
}
|
||||
|
||||
// pendingMsgs constructs an array of sdk.Msg. This method will check pending transactions and convert
|
||||
// those transactions into ethermint messages.
|
||||
func (api *PublicEthereumAPI) pendingMsgs() ([]sdk.Msg, error) {
|
||||
// nolint: prealloc
|
||||
var msgs []sdk.Msg
|
||||
|
||||
pendingTxs, err := api.PendingTransactions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, pendingTx := range pendingTxs {
|
||||
// NOTE: we have to construct the EVM transaction instead of just casting from the tendermint
|
||||
// transactions because PendingTransactions only checks for MsgEthereumTx messages.
|
||||
|
||||
pendingTo := sdk.AccAddress(pendingTx.To.Bytes())
|
||||
pendingFrom := sdk.AccAddress(pendingTx.From.Bytes())
|
||||
pendingGas, err := hexutil.DecodeUint64(pendingTx.Gas.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pendingValue := pendingTx.Value.ToInt()
|
||||
pendingGasPrice := new(big.Int).SetUint64(ethermint.DefaultGasPrice)
|
||||
if pendingTx.GasPrice != nil {
|
||||
pendingGasPrice = pendingTx.GasPrice.ToInt()
|
||||
}
|
||||
|
||||
pendingData := pendingTx.Input
|
||||
|
||||
msg := evmtypes.NewMsgEthermint(0, &pendingTo, sdk.NewIntFromBigInt(pendingValue), pendingGas,
|
||||
sdk.NewIntFromBigInt(pendingGasPrice), pendingData, pendingFrom)
|
||||
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
// accountNonce returns looks up the transaction nonce count for a given address. If the pending boolean
|
||||
// is set to true, it will add to the counter all the uncommitted EVM transactions sent from the address.
|
||||
// NOTE: The function returns no error if the account doesn't exist.
|
||||
func (api *PublicEthereumAPI) accountNonce(
|
||||
clientCtx clientcontext.CLIContext, address common.Address, pending bool,
|
||||
) (uint64, error) {
|
||||
// Get nonce (sequence) from sender account
|
||||
from := sdk.AccAddress(address.Bytes())
|
||||
|
||||
// use a the given client context in case its wrapped with a custom height
|
||||
accRet := authtypes.NewAccountRetriever(clientCtx)
|
||||
|
||||
if err := accRet.EnsureExists(from); err != nil {
|
||||
// account doesn't exist yet, return 0
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
_, nonce, err := accRet.GetAccountNumberSequence(from)
|
||||
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 := api.backend.PendingTransactions()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 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 == address {
|
||||
nonce++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nonce, nil
|
||||
}
|
||||
|
||||
+4
-1
@@ -18,6 +18,9 @@ const (
|
||||
|
||||
// EarliestBlockNumber mapping from "earliest" to 1 for tm query (earliest query not supported)
|
||||
EarliestBlockNumber = BlockNumber(1)
|
||||
|
||||
// PendingBlockNumber mapping from "pending" to -1 for tm query
|
||||
PendingBlockNumber = BlockNumber(-1)
|
||||
)
|
||||
|
||||
// NewBlockNumber creates a new BlockNumber instance.
|
||||
@@ -45,7 +48,7 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
|
||||
*bn = LatestBlockNumber
|
||||
return nil
|
||||
case "pending":
|
||||
*bn = LatestBlockNumber
|
||||
*bn = PendingBlockNumber
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -31,7 +31,7 @@ func RawTxToEthTx(clientCtx clientcontext.CLIContext, bz []byte) (*evmtypes.MsgE
|
||||
|
||||
ethTx, ok := tx.(evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{})
|
||||
return nil, fmt.Errorf("invalid transaction type %T, expected %T", tx, evmtypes.MsgEthereumTx{})
|
||||
}
|
||||
return ðTx, nil
|
||||
}
|
||||
@@ -90,7 +90,7 @@ func EthBlockFromTendermint(clientCtx clientcontext.CLIContext, block *tmtypes.B
|
||||
|
||||
bloom := bloomRes.Bloom
|
||||
|
||||
return formatBlock(block.Header, block.Size(), gasLimit, gasUsed, transactions, bloom), nil
|
||||
return FormatBlock(block.Header, block.Size(), gasLimit, gasUsed, transactions, bloom), nil
|
||||
}
|
||||
|
||||
// EthHeaderFromTendermint is an util function that returns an Ethereum Header
|
||||
@@ -150,7 +150,9 @@ func BlockMaxGasFromConsensusParams(_ context.Context, clientCtx clientcontext.C
|
||||
return gasLimit, nil
|
||||
}
|
||||
|
||||
func formatBlock(
|
||||
// FormatBlock creates an ethereum block from a tendermint header and ethereum-formatted
|
||||
// transactions.
|
||||
func FormatBlock(
|
||||
header tmtypes.Header, size int, gasLimit int64,
|
||||
gasUsed *big.Int, transactions interface{}, bloom ethtypes.Bloom,
|
||||
) map[string]interface{} {
|
||||
|
||||
Reference in New Issue
Block a user