rpc: implement eth_getPendingTransactions
(#259)
* Implement `eth_getPendingTransactions` Closes #244 * refactor repeatitive code * Update ethereum/rpc/namespaces/eth/api.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> * Update ethereum/rpc/namespaces/eth/api.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> * Update ethereum/rpc/namespaces/eth/api.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> * Update ethereum/rpc/namespaces/eth/api.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> * test UnwrapEthereumMsg Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
parent
8d51a70d6d
commit
1a48e09e78
@ -612,40 +612,18 @@ func (e *PublicAPI) GetTransactionByHash(hash common.Hash) (*rpctypes.RPCTransac
|
||||
}
|
||||
|
||||
for _, tx := range txs {
|
||||
if tx == nil {
|
||||
return nil, fmt.Errorf("invalid tx in mempool")
|
||||
}
|
||||
|
||||
if len((*tx).GetMsgs()) != 1 {
|
||||
continue
|
||||
}
|
||||
msg, ok := (*tx).GetMsgs()[0].(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
txhash := msg.AsTransaction().Hash()
|
||||
if txhash != hash {
|
||||
continue
|
||||
}
|
||||
|
||||
from, err := msg.GetSender(e.chainIDEpoch)
|
||||
msg, err := evmtypes.UnwrapEthereumMsg(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// not ethereum tx
|
||||
continue
|
||||
}
|
||||
|
||||
data, err := evmtypes.UnpackTxData(msg.Data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unpack tx data: %w", err)
|
||||
}
|
||||
|
||||
rpctx, err := rpctypes.NewTransactionFromData(
|
||||
data,
|
||||
from,
|
||||
hash,
|
||||
rpctx, err := rpctypes.NewTransactionFromMsg(
|
||||
msg,
|
||||
common.Hash{},
|
||||
uint64(0),
|
||||
uint64(0),
|
||||
e.chainIDEpoch,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -666,33 +644,18 @@ func (e *PublicAPI) GetTransactionByHash(hash common.Hash) (*rpctypes.RPCTransac
|
||||
return nil, fmt.Errorf("failed to decode tx: %w", err)
|
||||
}
|
||||
|
||||
if len(tx.GetMsgs()) != 1 {
|
||||
e.logger.Debugln("invalid tx")
|
||||
return nil, fmt.Errorf("invalid tx type: %T", tx)
|
||||
}
|
||||
msg, ok := tx.GetMsgs()[0].(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
e.logger.Debugln("invalid tx")
|
||||
return nil, fmt.Errorf("invalid tx type: %T", tx)
|
||||
}
|
||||
|
||||
from, err := msg.GetSender(e.chainIDEpoch)
|
||||
msg, err := evmtypes.UnwrapEthereumMsg(&tx)
|
||||
if err != nil {
|
||||
e.logger.WithError(err).Debugln("invalid tx")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := evmtypes.UnpackTxData(msg.Data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unpack tx data: %w", err)
|
||||
}
|
||||
|
||||
return rpctypes.NewTransactionFromData(
|
||||
data,
|
||||
from,
|
||||
hash,
|
||||
return rpctypes.NewTransactionFromMsg(
|
||||
msg,
|
||||
common.BytesToHash(resBlock.Block.Hash()),
|
||||
uint64(res.Height),
|
||||
uint64(res.Index),
|
||||
e.chainIDEpoch,
|
||||
)
|
||||
}
|
||||
|
||||
@ -719,31 +682,18 @@ func (e *PublicAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexu
|
||||
return nil, fmt.Errorf("failed to decode tx: %w", err)
|
||||
}
|
||||
|
||||
if len(tx.GetMsgs()) != 1 {
|
||||
e.logger.Debugln("invalid tx")
|
||||
return nil, fmt.Errorf("invalid tx type: %T", tx)
|
||||
}
|
||||
msg, ok := tx.GetMsgs()[0].(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
e.logger.Debugln("invalid tx")
|
||||
return nil, fmt.Errorf("invalid tx type: %T", tx)
|
||||
}
|
||||
|
||||
txHash := msg.AsTransaction().Hash()
|
||||
|
||||
txData, err := evmtypes.UnpackTxData(msg.Data)
|
||||
msg, err := evmtypes.UnwrapEthereumMsg(&tx)
|
||||
if err != nil {
|
||||
e.logger.WithError(err).Debugln("decoding failed")
|
||||
return nil, fmt.Errorf("failed to unpack tx data: %w", err)
|
||||
e.logger.WithError(err).Debugln("invalid tx")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rpctypes.NewTransactionFromData(
|
||||
txData,
|
||||
common.HexToAddress(msg.From),
|
||||
txHash,
|
||||
return rpctypes.NewTransactionFromMsg(
|
||||
msg,
|
||||
hash,
|
||||
uint64(resBlock.Block.Height),
|
||||
uint64(idx),
|
||||
e.chainIDEpoch,
|
||||
)
|
||||
}
|
||||
|
||||
@ -770,31 +720,18 @@ func (e *PublicAPI) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockN
|
||||
return nil, fmt.Errorf("failed to decode tx: %w", err)
|
||||
}
|
||||
|
||||
if len(tx.GetMsgs()) != 1 {
|
||||
e.logger.Debugln("invalid tx")
|
||||
return nil, fmt.Errorf("invalid tx type: %T", tx)
|
||||
}
|
||||
msg, ok := tx.GetMsgs()[0].(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
e.logger.Debugln("invalid tx")
|
||||
return nil, fmt.Errorf("invalid tx type: %T", tx)
|
||||
}
|
||||
|
||||
txHash := msg.AsTransaction().Hash()
|
||||
|
||||
txData, err := evmtypes.UnpackTxData(msg.Data)
|
||||
msg, err := evmtypes.UnwrapEthereumMsg(&tx)
|
||||
if err != nil {
|
||||
e.logger.WithError(err).Debugln("decoding failed")
|
||||
return nil, fmt.Errorf("failed to unpack tx data: %w", err)
|
||||
e.logger.WithError(err).Debugln("invalid tx")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rpctypes.NewTransactionFromData(
|
||||
txData,
|
||||
common.HexToAddress(msg.From),
|
||||
txHash,
|
||||
return rpctypes.NewTransactionFromMsg(
|
||||
msg,
|
||||
common.BytesToHash(resBlock.Block.Hash()),
|
||||
uint64(resBlock.Block.Height),
|
||||
uint64(idx),
|
||||
e.chainIDEpoch,
|
||||
)
|
||||
}
|
||||
|
||||
@ -820,15 +757,10 @@ func (e *PublicAPI) GetTransactionReceipt(hash common.Hash) (map[string]interfac
|
||||
return nil, fmt.Errorf("failed to decode tx: %w", err)
|
||||
}
|
||||
|
||||
if len(tx.GetMsgs()) != 1 {
|
||||
e.logger.Debugln("invalid tx")
|
||||
return nil, fmt.Errorf("invalid tx type: %T", tx)
|
||||
}
|
||||
|
||||
msg, ok := tx.GetMsgs()[0].(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
e.logger.Debugln("invalid tx")
|
||||
return nil, fmt.Errorf("invalid tx type: %T", tx)
|
||||
msg, err := evmtypes.UnwrapEthereumMsg(&tx)
|
||||
if err != nil {
|
||||
e.logger.WithError(err).Debugln("invalid tx")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txData, err := evmtypes.UnpackTxData(msg.Data)
|
||||
@ -911,8 +843,34 @@ func (e *PublicAPI) GetTransactionReceipt(hash common.Hash) (map[string]interfac
|
||||
func (e *PublicAPI) PendingTransactions() ([]*rpctypes.RPCTransaction, error) {
|
||||
e.logger.Debugln("eth_getPendingTransactions")
|
||||
|
||||
// FIXME https://github.com/tharsis/ethermint/issues/244
|
||||
return []*rpctypes.RPCTransaction{}, nil
|
||||
txs, err := e.backend.PendingTransactions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*rpctypes.RPCTransaction, 0, len(txs))
|
||||
for _, tx := range txs {
|
||||
msg, err := evmtypes.UnwrapEthereumMsg(tx)
|
||||
if err != nil {
|
||||
// not valid ethereum tx
|
||||
continue
|
||||
}
|
||||
|
||||
rpctx, err := rpctypes.NewTransactionFromMsg(
|
||||
msg,
|
||||
common.Hash{},
|
||||
uint64(0),
|
||||
uint64(0),
|
||||
e.chainIDEpoch,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result = append(result, rpctx)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetUncleByBlockHashAndIndex returns the uncle identified by hash and index. Always returns nil.
|
||||
@ -1095,16 +1053,12 @@ func (e *PublicAPI) getAccountNonce(accAddr common.Address, pending bool, height
|
||||
// add the uncommitted txs to the nonce counter
|
||||
// only supports `MsgEthereumTx` style tx
|
||||
for _, tx := range pendingTxs {
|
||||
if tx == nil {
|
||||
continue
|
||||
}
|
||||
if len((*tx).GetMsgs()) != 1 {
|
||||
continue
|
||||
}
|
||||
msg, ok := (*tx).GetMsgs()[0].(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
msg, err := evmtypes.UnwrapEthereumMsg(tx)
|
||||
if err != nil {
|
||||
// not ethereum tx
|
||||
continue
|
||||
}
|
||||
|
||||
sender, err := msg.GetSender(e.chainIDEpoch)
|
||||
if err != nil {
|
||||
continue
|
||||
|
@ -236,6 +236,27 @@ func ErrRevertedWith(data []byte) DataError {
|
||||
}
|
||||
}
|
||||
|
||||
// NewTransactionFromMsg returns a transaction that will serialize to the RPC
|
||||
// representation, with the given location metadata set (if available).
|
||||
func NewTransactionFromMsg(
|
||||
msg *evmtypes.MsgEthereumTx,
|
||||
blockHash common.Hash,
|
||||
blockNumber, index uint64,
|
||||
chainID *big.Int,
|
||||
) (*RPCTransaction, error) {
|
||||
from, err := msg.GetSender(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := evmtypes.UnpackTxData(msg.Data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unpack tx data: %w", err)
|
||||
}
|
||||
|
||||
return NewTransactionFromData(data, from, msg.AsTransaction().Hash(), blockHash, blockNumber, index)
|
||||
}
|
||||
|
||||
// NewTransactionFromData returns a transaction that will serialize to the RPC
|
||||
// representation, with the given location metadata set (if available).
|
||||
func NewTransactionFromData(
|
||||
|
@ -282,6 +282,12 @@ func TestEth_Pending_GetTransactionByHash(t *testing.T) {
|
||||
err = json.Unmarshal(rpcRes.Result, &pendingBlockTx)
|
||||
require.NoError(t, err)
|
||||
|
||||
txsRes := Call(t, "eth_getPendingTransactions", []interface{}{})
|
||||
var pendingTxs []map[string]interface{}
|
||||
err = json.Unmarshal(txsRes.Result, &pendingTxs)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, pendingTxs)
|
||||
|
||||
// verify the pending tx has all the correct fields from the tx sent.
|
||||
require.NotEmpty(t, pendingBlockTx)
|
||||
require.NotEmpty(t, pendingBlockTx["hash"])
|
||||
|
@ -37,6 +37,7 @@ func NewTx(
|
||||
gasLimit uint64, gasPrice *big.Int, input []byte, accesses *ethtypes.AccessList,
|
||||
) *MsgEthereumTx {
|
||||
return newMsgEthereumTx(chainID, nonce, to, amount, gasLimit, gasPrice, input, accesses)
|
||||
|
||||
}
|
||||
|
||||
// NewTxContract returns a reference to a new Ethereum transaction
|
||||
|
@ -1,6 +1,8 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
log "github.com/xlab/suplog"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
@ -50,3 +52,20 @@ func DecodeTransactionLogs(data []byte) (TransactionLogs, error) {
|
||||
}
|
||||
return logs, nil
|
||||
}
|
||||
|
||||
// UnwrapEthereumMsg extract MsgEthereumTx from wrapping sdk.Tx
|
||||
func UnwrapEthereumMsg(tx *sdk.Tx) (*MsgEthereumTx, error) {
|
||||
if tx == nil {
|
||||
return nil, fmt.Errorf("invalid tx: nil")
|
||||
}
|
||||
|
||||
if len((*tx).GetMsgs()) != 1 {
|
||||
return nil, fmt.Errorf("invalid tx type: %T", tx)
|
||||
}
|
||||
msg, ok := (*tx).GetMsgs()[0].(*MsgEthereumTx)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid tx type: %T", tx)
|
||||
}
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
@ -1,11 +1,17 @@
|
||||
package types
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
"github.com/tharsis/ethermint/app"
|
||||
"github.com/tharsis/ethermint/crypto/ethsecp256k1"
|
||||
"github.com/tharsis/ethermint/encoding"
|
||||
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@ -27,9 +33,9 @@ func GenerateEthAddress() ethcmn.Address {
|
||||
func TestEvmDataEncoding(t *testing.T) {
|
||||
ret := []byte{0x5, 0x8}
|
||||
|
||||
data := &MsgEthereumTxResponse{
|
||||
data := &evmtypes.MsgEthereumTxResponse{
|
||||
Hash: common.BytesToHash([]byte("hash")).String(),
|
||||
Logs: []*Log{{
|
||||
Logs: []*evmtypes.Log{{
|
||||
Data: []byte{1, 2, 3, 4},
|
||||
BlockNumber: 17,
|
||||
}},
|
||||
@ -40,15 +46,36 @@ func TestEvmDataEncoding(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
txData := &sdk.TxMsgData{
|
||||
Data: []*sdk.MsgData{{MsgType: TypeMsgEthereumTx, Data: enc}},
|
||||
Data: []*sdk.MsgData{{MsgType: evmtypes.TypeMsgEthereumTx, Data: enc}},
|
||||
}
|
||||
|
||||
txDataBz, err := proto.Marshal(txData)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := DecodeTxResponse(txDataBz)
|
||||
res, err := evmtypes.DecodeTxResponse(txDataBz)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, res)
|
||||
require.Equal(t, data.Logs, res.Logs)
|
||||
require.Equal(t, ret, res.Ret)
|
||||
}
|
||||
|
||||
func TestUnwrapEthererumMsg(t *testing.T) {
|
||||
_, err := evmtypes.UnwrapEthereumMsg(nil)
|
||||
require.NotNil(t, err)
|
||||
|
||||
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
|
||||
clientCtx := client.Context{}.WithTxConfig(encodingConfig.TxConfig)
|
||||
builder, _ := clientCtx.TxConfig.NewTxBuilder().(authtx.ExtensionOptionsTxBuilder)
|
||||
|
||||
tx := builder.GetTx().(sdk.Tx)
|
||||
_, err = evmtypes.UnwrapEthereumMsg(&tx)
|
||||
require.NotNil(t, err)
|
||||
|
||||
msg := evmtypes.NewTx(big.NewInt(1), 0, &common.Address{}, big.NewInt(0), 0, big.NewInt(0), []byte{}, nil)
|
||||
err = builder.SetMsgs(msg)
|
||||
|
||||
tx = builder.GetTx().(sdk.Tx)
|
||||
msg_, err := evmtypes.UnwrapEthereumMsg(&tx)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, msg_, msg)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user