Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

return eth tx hash to client #202

Merged
merged 2 commits into from
Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 2 additions & 3 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
)
Expand Down
19 changes: 8 additions & 11 deletions ethereum/rpc/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
Expand Down
48 changes: 27 additions & 21 deletions ethereum/rpc/namespaces/eth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -686,11 +680,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
Expand Down Expand Up @@ -718,9 +727,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),
Expand Down Expand Up @@ -754,15 +760,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,
Expand Down Expand Up @@ -807,9 +815,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,
Expand All @@ -825,7 +831,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
Expand Down
27 changes: 21 additions & 6 deletions x/evm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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
}
Expand All @@ -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
Expand Down
5 changes: 2 additions & 3 deletions x/evm/keeper/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT

evm := k.NewEVM(msg, ethCfg)

k.SetTxHashTransient(tx.Hash())
k.IncreaseTxIndexTransient()

// set the original gas meter to apply the message and perform the state transition
Expand All @@ -144,9 +145,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)
Expand Down
24 changes: 3 additions & 21 deletions x/evm/keeper/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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),
)
Expand Down
13 changes: 3 additions & 10 deletions x/evm/keeper/statedb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -501,7 +493,7 @@ func (suite *KeeperTestSuite) TestAddLog() {
}{
{
"tx hash from message",
tmHash,
txHash,
&ethtypes.Log{
Address: addr,
},
Expand All @@ -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)

Expand Down
2 changes: 2 additions & 0 deletions x/evm/types/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const (
prefixTransientRefund
prefixTransientAccessListAddress
prefixTransientAccessListSlot
prefixTransientTxHash
)

// KVStore key prefixes
Expand All @@ -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
Expand Down