fix: return ethereum-formatted tx hash to client (#202)
* return eth tx hash to client Closes #67 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> change GetTxByEthHash to method add entry to changelog * use eth tx hash internally
This commit is contained in:
parent
5ba8ffe669
commit
0113b4d2c0
@ -51,6 +51,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
* The `ContractAddress`, `Bloom` have been removed from the `MsgEthereumTxResponse` and the
|
||||
response now contains the ethereum-formatted `Hash` in hex format.
|
||||
* (eth) [\#845](https://github.com/cosmos/ethermint/pull/845) The `eth` namespace must be included in the list of API's as default to run the rpc server without error.
|
||||
* (evm) [#202](https://github.com/tharsis/ethermint/pull/202) Web3 api `SendTransaction`/`SendRawTransaction` returns ethereum compatible transaction hash, and query api `GetTransaction*` also accept that.
|
||||
|
||||
### Improvements
|
||||
|
||||
|
@ -247,14 +247,13 @@ func NewEthermintApp(
|
||||
appCodec := encodingConfig.Marshaler
|
||||
cdc := encodingConfig.Amino
|
||||
interfaceRegistry := encodingConfig.InterfaceRegistry
|
||||
txDecoder := encodingConfig.TxConfig.TxDecoder()
|
||||
|
||||
// NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
|
||||
bApp := baseapp.NewBaseApp(
|
||||
appName,
|
||||
logger,
|
||||
db,
|
||||
txDecoder,
|
||||
encodingConfig.TxConfig.TxDecoder(),
|
||||
baseAppOptions...,
|
||||
)
|
||||
bApp.SetCommitMultiStoreTracer(traceStore)
|
||||
@ -337,7 +336,7 @@ func NewEthermintApp(
|
||||
|
||||
// Create Ethermint keepers
|
||||
app.EvmKeeper = evmkeeper.NewKeeper(
|
||||
appCodec, txDecoder, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], app.GetSubspace(evmtypes.ModuleName),
|
||||
appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], app.GetSubspace(evmtypes.ModuleName),
|
||||
app.AccountKeeper, app.BankKeeper, app.StakingKeeper,
|
||||
bApp.Trace(), // debug EVM based on Baseapp options
|
||||
)
|
||||
|
@ -138,23 +138,20 @@ func (e *EVMBackend) EthBlockFromTendermint(
|
||||
ethRPCTxs := []interface{}{}
|
||||
|
||||
for i, txBz := range block.Txs {
|
||||
// TODO: use msg.AsTransaction.Hash() for txHash once hashing is fixed on Tendermint
|
||||
// https://github.com/tendermint/tendermint/issues/6539
|
||||
hash := common.BytesToHash(txBz.Hash())
|
||||
|
||||
tx, gas := types.DecodeTx(e.clientCtx, txBz)
|
||||
|
||||
gasUsed += gas
|
||||
|
||||
msg, isEthTx := tx.(*evmtypes.MsgEthereumTx)
|
||||
|
||||
if fullTx {
|
||||
if !isEthTx {
|
||||
// TODO: eventually support Cosmos txs in the block
|
||||
continue
|
||||
}
|
||||
if !isEthTx {
|
||||
// TODO: eventually support Cosmos txs in the block
|
||||
continue
|
||||
}
|
||||
|
||||
tx, err := types.NewTransactionFromData(
|
||||
hash := msg.AsTransaction().Hash()
|
||||
if fullTx {
|
||||
ethTx, err := types.NewTransactionFromData(
|
||||
msg.Data,
|
||||
common.HexToAddress(msg.From),
|
||||
hash,
|
||||
@ -163,7 +160,7 @@ func (e *EVMBackend) EthBlockFromTendermint(
|
||||
uint64(i),
|
||||
)
|
||||
|
||||
ethRPCTxs = append(ethRPCTxs, tx)
|
||||
ethRPCTxs = append(ethRPCTxs, ethTx)
|
||||
|
||||
if err != nil {
|
||||
e.logger.WithError(err).Debugln("NewTransactionFromData for receipt failed", "hash", hash.Hex)
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@ -415,10 +415,7 @@ func (e *PublicAPI) SendTransaction(args rpctypes.SendTxArgs) (common.Hash, erro
|
||||
return common.Hash{}, err
|
||||
}
|
||||
|
||||
// TODO: use msg.AsTransaction.Hash() for txHash once hashing is fixed on Tendermint
|
||||
// https://github.com/tendermint/tendermint/issues/6539
|
||||
tmTx := tmtypes.Tx(txBytes)
|
||||
txHash := common.BytesToHash(tmTx.Hash())
|
||||
txHash := msg.AsTransaction().Hash()
|
||||
|
||||
// Broadcast transaction in sync mode (default)
|
||||
// NOTE: If error is encountered on the node, the broadcast will not return an error
|
||||
@ -488,10 +485,7 @@ func (e *PublicAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error)
|
||||
return common.Hash{}, err
|
||||
}
|
||||
|
||||
// TODO: use msg.AsTransaction.Hash() for txHash once hashing is fixed on Tendermint
|
||||
// https://github.com/tendermint/tendermint/issues/6539
|
||||
tmTx := tmtypes.Tx(txBytes)
|
||||
txHash := common.BytesToHash(tmTx.Hash())
|
||||
txHash := ethereumTx.AsTransaction().Hash()
|
||||
|
||||
syncCtx := e.clientCtx.WithBroadcastMode(flags.BroadcastSync)
|
||||
rsp, err := syncCtx.BroadcastTx(txBytes)
|
||||
@ -682,11 +676,26 @@ func (e *PublicAPI) GetBlockByNumber(ethBlockNum rpctypes.BlockNumber, fullTx bo
|
||||
return e.backend.GetBlockByNumber(ethBlockNum, fullTx)
|
||||
}
|
||||
|
||||
// GetTxByEthHash uses `/tx_query` to find transaction by ethereum tx hash
|
||||
// TODO: Don't need to convert once hashing is fixed on Tendermint
|
||||
// https://github.com/tendermint/tendermint/issues/6539
|
||||
func (e *PublicAPI) GetTxByEthHash(hash common.Hash) (*tmrpctypes.ResultTx, error) {
|
||||
query := fmt.Sprintf("%s.%s='%s'", evmtypes.TypeMsgEthereumTx, evmtypes.AttributeKeyEthereumTxHash, hash.Hex())
|
||||
resTxs, err := e.clientCtx.Client.TxSearch(e.ctx, query, false, nil, nil, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(resTxs.Txs) == 0 {
|
||||
return nil, errors.Errorf("ethereum tx not found for hash %s", hash.Hex())
|
||||
}
|
||||
return resTxs.Txs[0], nil
|
||||
}
|
||||
|
||||
// GetTransactionByHash returns the transaction identified by hash.
|
||||
func (e *PublicAPI) GetTransactionByHash(hash common.Hash) (*rpctypes.RPCTransaction, error) {
|
||||
e.logger.Debugln("eth_getTransactionByHash", "hash", hash.Hex())
|
||||
|
||||
res, err := e.clientCtx.Client.Tx(e.ctx, hash.Bytes(), false)
|
||||
res, err := e.GetTxByEthHash(hash)
|
||||
if err != nil {
|
||||
e.logger.WithError(err).Debugln("tx not found", "hash", hash.Hex())
|
||||
return nil, nil
|
||||
@ -714,9 +723,6 @@ func (e *PublicAPI) GetTransactionByHash(hash common.Hash) (*rpctypes.RPCTransac
|
||||
return nil, fmt.Errorf("invalid tx type: %T", tx)
|
||||
}
|
||||
|
||||
// TODO: use msg.AsTransaction.Hash() for txHash once hashing is fixed on Tendermint
|
||||
// https://github.com/tendermint/tendermint/issues/6539
|
||||
|
||||
return rpctypes.NewTransactionFromData(
|
||||
msg.Data,
|
||||
common.HexToAddress(msg.From),
|
||||
@ -750,15 +756,17 @@ func (e *PublicAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexu
|
||||
return nil, fmt.Errorf("failed to decode tx: %w", err)
|
||||
}
|
||||
|
||||
msg, ok := tx.(*evmtypes.MsgEthereumTx)
|
||||
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)
|
||||
}
|
||||
|
||||
// TODO: use msg.AsTransaction.Hash() for txHash once hashing is fixed on Tendermint
|
||||
// https://github.com/tendermint/tendermint/issues/6539
|
||||
txHash := common.BytesToHash(txBz.Hash())
|
||||
txHash := msg.AsTransaction().Hash()
|
||||
|
||||
return rpctypes.NewTransactionFromData(
|
||||
msg.Data,
|
||||
@ -803,9 +811,7 @@ func (e *PublicAPI) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockN
|
||||
return nil, fmt.Errorf("invalid tx type: %T", tx)
|
||||
}
|
||||
|
||||
// TODO: use msg.AsTransaction.Hash() for txHash once hashing is fixed on Tendermint
|
||||
// https://github.com/tendermint/tendermint/issues/6539
|
||||
txHash := common.BytesToHash(txBz.Hash())
|
||||
txHash := msg.AsTransaction().Hash()
|
||||
|
||||
return rpctypes.NewTransactionFromData(
|
||||
msg.Data,
|
||||
@ -821,7 +827,7 @@ func (e *PublicAPI) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockN
|
||||
func (e *PublicAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) {
|
||||
e.logger.Debugln("eth_getTransactionReceipt", "hash", hash.Hex())
|
||||
|
||||
res, err := e.clientCtx.Client.Tx(e.ctx, hash.Bytes(), false)
|
||||
res, err := e.GetTxByEthHash(hash)
|
||||
if err != nil {
|
||||
e.logger.WithError(err).Debugln("tx not found", "hash", hash.Hex())
|
||||
return nil, nil
|
||||
|
@ -21,8 +21,7 @@ import (
|
||||
// to the StateDB interface.
|
||||
type Keeper struct {
|
||||
// Protobuf codec
|
||||
cdc codec.BinaryCodec
|
||||
txDecoder sdk.TxDecoder
|
||||
cdc codec.BinaryCodec
|
||||
// Store key required for the EVM Prefix KVStore. It is required by:
|
||||
// - storing Account's Storage State
|
||||
// - storing Account's Code
|
||||
@ -47,7 +46,7 @@ type Keeper struct {
|
||||
|
||||
// NewKeeper generates new evm module keeper
|
||||
func NewKeeper(
|
||||
cdc codec.BinaryCodec, txDecoder sdk.TxDecoder,
|
||||
cdc codec.BinaryCodec,
|
||||
storeKey, transientKey sdk.StoreKey, paramSpace paramtypes.Subspace,
|
||||
ak types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper,
|
||||
debug bool,
|
||||
@ -66,7 +65,6 @@ func NewKeeper(
|
||||
// NOTE: we pass in the parameter space to the CommitStateDB in order to use custom denominations for the EVM operations
|
||||
return &Keeper{
|
||||
cdc: cdc,
|
||||
txDecoder: txDecoder,
|
||||
paramSpace: paramSpace,
|
||||
accountKeeper: ak,
|
||||
bankKeeper: bankKeeper,
|
||||
@ -152,10 +150,27 @@ func (k Keeper) SetBlockBloomTransient(bloom *big.Int) {
|
||||
// Tx
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// GetTxHashTransient returns the hash of current processing transaction
|
||||
func (k Keeper) GetTxHashTransient() common.Hash {
|
||||
store := k.ctx.TransientStore(k.transientKey)
|
||||
bz := store.Get(types.KeyPrefixTransientTxHash)
|
||||
if len(bz) == 0 {
|
||||
return common.Hash{}
|
||||
}
|
||||
|
||||
return common.BytesToHash(bz)
|
||||
}
|
||||
|
||||
// SetTxHashTransient set the hash of processing transaction
|
||||
func (k Keeper) SetTxHashTransient(hash common.Hash) {
|
||||
store := k.ctx.TransientStore(k.transientKey)
|
||||
store.Set(types.KeyPrefixTransientTxHash, hash.Bytes())
|
||||
}
|
||||
|
||||
// GetTxIndexTransient returns EVM transaction index on the current block.
|
||||
func (k Keeper) GetTxIndexTransient() uint64 {
|
||||
store := k.ctx.TransientStore(k.transientKey)
|
||||
bz := store.Get(types.KeyPrefixTransientBloom)
|
||||
bz := store.Get(types.KeyPrefixTransientTxIndex)
|
||||
if len(bz) == 0 {
|
||||
return 0
|
||||
}
|
||||
@ -168,7 +183,7 @@ func (k Keeper) GetTxIndexTransient() uint64 {
|
||||
func (k Keeper) IncreaseTxIndexTransient() {
|
||||
txIndex := k.GetTxIndexTransient()
|
||||
store := k.ctx.TransientStore(k.transientKey)
|
||||
store.Set(types.KeyPrefixTransientBloom, sdk.Uint64ToBigEndian(txIndex+1))
|
||||
store.Set(types.KeyPrefixTransientTxIndex, sdk.Uint64ToBigEndian(txIndex+1))
|
||||
}
|
||||
|
||||
// ResetRefundTransient resets the available refund amount to 0
|
||||
|
@ -128,6 +128,7 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT
|
||||
|
||||
evm := k.NewEVM(msg, ethCfg)
|
||||
|
||||
k.SetTxHashTransient(tx.Hash())
|
||||
k.IncreaseTxIndexTransient()
|
||||
|
||||
// create an ethereum StateTransition instance and run TransitionDb
|
||||
@ -136,9 +137,7 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT
|
||||
return nil, stacktrace.Propagate(err, "failed to apply ethereum core message")
|
||||
}
|
||||
|
||||
// NOTE: we set up the transaction hash from tendermint as it is the format expected by the application:
|
||||
// Remove once hashing is fixed on Tendermint. See https://github.com/tendermint/tendermint/issues/6539
|
||||
txHash := common.BytesToHash(tmtypes.Tx(k.ctx.TxBytes()).Hash())
|
||||
txHash := tx.Hash()
|
||||
res.Hash = txHash.Hex()
|
||||
|
||||
logs := k.GetTxLogs(txHash)
|
||||
|
@ -10,8 +10,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store/prefix"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
@ -588,35 +586,19 @@ func (k *Keeper) RevertToSnapshot(_ int) {}
|
||||
// context. This function also fills in the tx hash, block hash, tx index and log index fields before setting the log
|
||||
// to store.
|
||||
func (k *Keeper) AddLog(log *ethtypes.Log) {
|
||||
tx, err := k.txDecoder(k.ctx.TxBytes())
|
||||
if err != nil {
|
||||
// safety check, should be checked when processing the tx
|
||||
panic(err)
|
||||
}
|
||||
// NOTE: tx length checked on AnteHandler
|
||||
ethTx, ok := tx.GetMsgs()[0].(*types.MsgEthereumTx)
|
||||
if !ok {
|
||||
panic("invalid ethereum tx")
|
||||
}
|
||||
|
||||
// NOTE: we set up the transaction hash from tendermint as it is the format expected by the application:
|
||||
// Remove once hashing is fixed on Tendermint. See https://github.com/tendermint/tendermint/issues/6539
|
||||
key := common.BytesToHash(tmtypes.Tx(k.ctx.TxBytes()).Hash())
|
||||
log.TxHash = common.HexToHash(ethTx.Hash)
|
||||
|
||||
log.BlockHash = common.BytesToHash(k.ctx.HeaderHash())
|
||||
log.TxIndex = uint(k.GetTxIndexTransient())
|
||||
log.TxHash = k.GetTxHashTransient()
|
||||
|
||||
logs := k.GetTxLogs(key)
|
||||
logs := k.GetTxLogs(log.TxHash)
|
||||
|
||||
log.Index = uint(len(logs))
|
||||
logs = append(logs, log)
|
||||
|
||||
k.SetLogs(key, logs)
|
||||
k.SetLogs(log.TxHash, logs)
|
||||
|
||||
k.Logger(k.ctx).Debug(
|
||||
"log added",
|
||||
"tx-hash-tendermint", key.Hex(),
|
||||
"tx-hash-ethereum", log.TxHash.Hex(),
|
||||
"log-index", int(log.Index),
|
||||
)
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
@ -483,15 +482,8 @@ func (suite *KeeperTestSuite) TestAddLog() {
|
||||
msg.From = addr.Hex()
|
||||
|
||||
tx := suite.CreateTestTx(msg, privKey)
|
||||
txBz, err := suite.clientCtx.TxConfig.TxEncoder()(tx)
|
||||
suite.Require().NoError(err)
|
||||
tmHash := common.BytesToHash(tmtypes.Tx(txBz).Hash())
|
||||
|
||||
msg, _ = tx.GetMsgs()[0].(*evmtypes.MsgEthereumTx)
|
||||
ethTx := msg.AsTransaction()
|
||||
txHash := ethTx.Hash()
|
||||
|
||||
suite.app.EvmKeeper.WithContext(suite.ctx.WithTxBytes(txBz))
|
||||
txHash := msg.AsTransaction().Hash()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
@ -501,7 +493,7 @@ func (suite *KeeperTestSuite) TestAddLog() {
|
||||
}{
|
||||
{
|
||||
"tx hash from message",
|
||||
tmHash,
|
||||
txHash,
|
||||
ðtypes.Log{
|
||||
Address: addr,
|
||||
},
|
||||
@ -518,6 +510,7 @@ func (suite *KeeperTestSuite) TestAddLog() {
|
||||
tc.malleate()
|
||||
|
||||
prev := suite.app.EvmKeeper.GetTxLogs(tc.hash)
|
||||
suite.app.EvmKeeper.SetTxHashTransient(tc.hash)
|
||||
suite.app.EvmKeeper.AddLog(tc.log)
|
||||
post := suite.app.EvmKeeper.GetTxLogs(tc.hash)
|
||||
|
||||
|
@ -42,6 +42,7 @@ const (
|
||||
prefixTransientRefund
|
||||
prefixTransientAccessListAddress
|
||||
prefixTransientAccessListSlot
|
||||
prefixTransientTxHash
|
||||
)
|
||||
|
||||
// KVStore key prefixes
|
||||
@ -63,6 +64,7 @@ var (
|
||||
KeyPrefixTransientRefund = []byte{prefixTransientRefund}
|
||||
KeyPrefixTransientAccessListAddress = []byte{prefixTransientAccessListAddress}
|
||||
KeyPrefixTransientAccessListSlot = []byte{prefixTransientAccessListSlot}
|
||||
KeyPrefixTransientTxHash = []byte{prefixTransientTxHash}
|
||||
)
|
||||
|
||||
// BloomKey defines the store key for a block Bloom
|
||||
|
Loading…
Reference in New Issue
Block a user