evm: fix AddLog unmarshaling tx (#192)

* fix `AddLog` unmarshaling tx

Closes #187

* use cosmos tx in AddLog unit test

* Apply suggestions from code review

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
yihuang 2021-06-29 18:54:29 +08:00 committed by GitHub
parent efb90f9922
commit 336703cfc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 72 additions and 43 deletions

View File

@ -229,13 +229,14 @@ func NewEthermintApp(
appCodec := encodingConfig.Marshaler appCodec := encodingConfig.Marshaler
cdc := encodingConfig.Amino cdc := encodingConfig.Amino
interfaceRegistry := encodingConfig.InterfaceRegistry interfaceRegistry := encodingConfig.InterfaceRegistry
txDecoder := encodingConfig.TxConfig.TxDecoder()
// NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx // NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
bApp := baseapp.NewBaseApp( bApp := baseapp.NewBaseApp(
appName, appName,
logger, logger,
db, db,
encodingConfig.TxConfig.TxDecoder(), txDecoder,
baseAppOptions..., baseAppOptions...,
) )
bApp.SetCommitMultiStoreTracer(traceStore) bApp.SetCommitMultiStoreTracer(traceStore)
@ -311,7 +312,7 @@ func NewEthermintApp(
// Create Ethermint keepers // Create Ethermint keepers
app.EvmKeeper = evmkeeper.NewKeeper( app.EvmKeeper = evmkeeper.NewKeeper(
appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], app.GetSubspace(evmtypes.ModuleName), appCodec, txDecoder, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], app.GetSubspace(evmtypes.ModuleName),
app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper,
) )

View File

@ -20,7 +20,8 @@ import (
// to the StateDB interface. // to the StateDB interface.
type Keeper struct { type Keeper struct {
// Protobuf codec // Protobuf codec
cdc codec.BinaryMarshaler cdc codec.BinaryMarshaler
txDecoder sdk.TxDecoder
// Store key required for the EVM Prefix KVStore. It is required by: // Store key required for the EVM Prefix KVStore. It is required by:
// - storing Account's Storage State // - storing Account's Storage State
// - storing Account's Code // - storing Account's Code
@ -37,6 +38,7 @@ type Keeper struct {
stakingKeeper types.StakingKeeper stakingKeeper types.StakingKeeper
ctx sdk.Context ctx sdk.Context
// chain ID number obtained from the context's chain id // chain ID number obtained from the context's chain id
eip155ChainID *big.Int eip155ChainID *big.Int
debug bool debug bool
@ -44,7 +46,7 @@ type Keeper struct {
// NewKeeper generates new evm module keeper // NewKeeper generates new evm module keeper
func NewKeeper( func NewKeeper(
cdc codec.BinaryMarshaler, storeKey, transientKey sdk.StoreKey, paramSpace paramtypes.Subspace, cdc codec.BinaryMarshaler, txDecoder sdk.TxDecoder, storeKey, transientKey sdk.StoreKey, paramSpace paramtypes.Subspace,
ak types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper, ak types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper,
) *Keeper { ) *Keeper {
// set KeyTable if it has not already been set // set KeyTable if it has not already been set
@ -55,6 +57,7 @@ func NewKeeper(
// NOTE: we pass in the parameter space to the CommitStateDB in order to use custom denominations for the EVM operations // NOTE: we pass in the parameter space to the CommitStateDB in order to use custom denominations for the EVM operations
return &Keeper{ return &Keeper{
cdc: cdc, cdc: cdc,
txDecoder: txDecoder,
paramSpace: paramSpace, paramSpace: paramSpace,
accountKeeper: ak, accountKeeper: ak,
bankKeeper: bankKeeper, bankKeeper: bankKeeper,

View File

@ -1,22 +1,25 @@
package keeper_test package keeper_test
import ( import (
"github.com/tharsis/ethermint/crypto/ethsecp256k1"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/tharsis/ethermint/app" "github.com/tharsis/ethermint/app"
"github.com/tharsis/ethermint/crypto/ethsecp256k1"
"github.com/tharsis/ethermint/encoding"
ethermint "github.com/tharsis/ethermint/types" ethermint "github.com/tharsis/ethermint/types"
"github.com/tharsis/ethermint/x/evm/types" "github.com/tharsis/ethermint/x/evm/types"
ethcmn "github.com/ethereum/go-ethereum/common" ethcmn "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
ethcrypto "github.com/ethereum/go-ethereum/crypto" ethcrypto "github.com/ethereum/go-ethereum/crypto"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
@ -37,6 +40,10 @@ type KeeperTestSuite struct {
queryClient types.QueryClient queryClient types.QueryClient
address ethcmn.Address address ethcmn.Address
consAddress sdk.ConsAddress consAddress sdk.ConsAddress
// for generate test tx
clientCtx client.Context
ethSigner ethtypes.Signer
} }
func (suite *KeeperTestSuite) SetupTest() { func (suite *KeeperTestSuite) SetupTest() {
@ -68,6 +75,10 @@ func (suite *KeeperTestSuite) SetupTest() {
suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator) suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator)
suite.app.StakingKeeper.SetValidator(suite.ctx, validator) suite.app.StakingKeeper.SetValidator(suite.ctx, validator)
suite.consAddress = sdk.ConsAddress(priv.PubKey().Address()) suite.consAddress = sdk.ConsAddress(priv.PubKey().Address())
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
suite.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig)
suite.ethSigner = ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
} }
func TestKeeperTestSuite(t *testing.T) { func TestKeeperTestSuite(t *testing.T) {

View File

@ -568,25 +568,21 @@ 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 // context. This function also fills in the tx hash, block hash, tx index and log index fields before setting the log
// to store. // to store.
func (k *Keeper) AddLog(log *ethtypes.Log) { func (k *Keeper) AddLog(log *ethtypes.Log) {
tx, err := k.txDecoder(k.ctx.TxBytes())
key := log.TxHash if err != nil {
// safety check, should be checked when processing the tx
if len(k.ctx.TxBytes()) > 0 { panic(err)
tx := &ethtypes.Transaction{}
if err := tx.UnmarshalBinary(k.ctx.TxBytes()); err != nil {
k.Logger(k.ctx).Error(
"ethereum tx unmarshaling failed",
"error", err,
)
return
}
// 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 = tx.Hash()
} }
// 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.BlockHash = common.BytesToHash(k.ctx.HeaderHash())
log.TxIndex = uint(k.GetTxIndexTransient()) log.TxIndex = uint(k.GetTxIndexTransient())

View File

@ -4,7 +4,11 @@ import (
"fmt" "fmt"
"math/big" "math/big"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
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" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
tmtypes "github.com/tendermint/tendermint/types" tmtypes "github.com/tendermint/tendermint/types"
@ -13,6 +17,7 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/tharsis/ethermint/tests" "github.com/tharsis/ethermint/tests"
"github.com/tharsis/ethermint/x/evm/types" "github.com/tharsis/ethermint/x/evm/types"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
) )
func (suite *KeeperTestSuite) TestCreateAccount() { func (suite *KeeperTestSuite) TestCreateAccount() {
@ -453,32 +458,47 @@ func (suite *KeeperTestSuite) TestSnapshot() {
suite.app.EvmKeeper.RevertToSnapshot(revision) // no-op suite.app.EvmKeeper.RevertToSnapshot(revision) // no-op
} }
func (suite *KeeperTestSuite) TestAddLog() { func (suite *KeeperTestSuite) CreateTestTx(msg *evmtypes.MsgEthereumTx, priv cryptotypes.PrivKey) authsigning.Tx {
addr := tests.GenerateAddress() option, err := codectypes.NewAnyWithValue(&evmtypes.ExtensionOptionsEthereumTx{})
msg := types.NewMsgEthereumTx(big.NewInt(1), 0, &suite.address, big.NewInt(1), 100000, big.NewInt(1), []byte("test"), nil) suite.Require().NoError(err)
tx := msg.AsTransaction()
txBz, err := tx.MarshalBinary() txBuilder := suite.clientCtx.TxConfig.NewTxBuilder()
builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder)
suite.Require().True(ok)
builder.SetExtensionOptions(option)
err = msg.Sign(suite.ethSigner, tests.NewSigner(priv))
suite.Require().NoError(err)
err = txBuilder.SetMsgs(msg)
suite.Require().NoError(err)
return txBuilder.GetTx()
}
func (suite *KeeperTestSuite) TestAddLog() {
addr, privKey := tests.NewAddrKey()
msg := types.NewMsgEthereumTx(big.NewInt(1), 0, &suite.address, big.NewInt(1), 100000, big.NewInt(1), []byte("test"), nil)
msg.From = addr.Hex()
tx := suite.CreateTestTx(msg, privKey)
txBz, err := suite.clientCtx.TxConfig.TxEncoder()(tx)
suite.Require().NoError(err) suite.Require().NoError(err)
txHash := tx.Hash()
tmHash := common.BytesToHash(tmtypes.Tx(txBz).Hash()) 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))
testCases := []struct { testCases := []struct {
name string name string
hash common.Hash hash common.Hash
log, expLog *ethtypes.Log // pre and post populating log fields log, expLog *ethtypes.Log // pre and post populating log fields
malleate func() malleate func()
}{ }{
{
"block hash not found",
common.Hash{},
&ethtypes.Log{
Address: addr,
},
&ethtypes.Log{
Address: addr,
},
func() {},
},
{ {
"tx hash from message", "tx hash from message",
tmHash, tmHash,
@ -489,9 +509,7 @@ func (suite *KeeperTestSuite) TestAddLog() {
Address: addr, Address: addr,
TxHash: txHash, TxHash: txHash,
}, },
func() { func() {},
suite.app.EvmKeeper.WithContext(suite.ctx.WithTxBytes(txBz))
},
}, },
} }