From 45c5416377f352abeeca5ead119d76e39b6425d2 Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 27 Sep 2024 14:06:24 +0200 Subject: [PATCH 1/7] feat: vm error fails msg and whole tx The change to return error during msg processing if VM reverts or errors out is a simple change, but it affect many places where it was expected to emit log. Failing Txns wrap the error reason into error that could be processed by ABCIInfo. It later is marshalled into JSON and put into log field of abci.ExecTxResult. Where it can be indexed by Ethermint's custom Tx indexer. We are moving away from pulling directly from CometBFT internal indexer for all EVM txns. Ameneded the tests to cover the new error handling and forwarding. TODO: tx_info_test is originally bad, needs a rewrite. --- go.mod | 1 + indexer/kv_indexer.go | 33 ++-- rpc/backend/blocks.go | 2 +- rpc/backend/tx_info.go | 27 +-- rpc/namespaces/ethereum/eth/api.go | 2 +- rpc/types/{events.go => parsed_tx.go} | 172 ++++++++---------- .../{events_test.go => parsed_tx_test.go} | 134 ++++---------- server/config/config.go | 2 +- server/indexer_cmd.go | 1 - server/start.go | 2 +- testutil/tx/eth.go | 46 ++++- x/evm/keeper/msg_server.go | 24 +++ x/evm/keeper/msg_server_test.go | 46 ++++- x/evm/keeper/state_transition.go | 3 + x/evm/keeper/state_transition_test.go | 10 +- x/evm/types/errors.go | 150 ++++++++++++++- x/evm/types/utils.go | 6 +- 17 files changed, 422 insertions(+), 239 deletions(-) rename rpc/types/{events.go => parsed_tx.go} (60%) rename rpc/types/{events_test.go => parsed_tx_test.go} (50%) diff --git a/go.mod b/go.mod index aeeb988a7c..5ede6d1e46 100644 --- a/go.mod +++ b/go.mod @@ -275,6 +275,7 @@ replace ( cosmossdk.io/client/v2 => github.com/InjectiveLabs/cosmos-sdk/client/v2 v2.0.0-20240904140803-b4127ecb5410 cosmossdk.io/store => github.com/InjectiveLabs/cosmos-sdk/store v0.0.0-20240904140803-b4127ecb5410 cosmossdk.io/x/tx => github.com/InjectiveLabs/cosmos-sdk/x/tx v0.0.0-20240904140803-b4127ecb5410 + cosmossdk.io/errors => ../cosmos-sdk/errors github.com/cosmos/cosmos-sdk => github.com/InjectiveLabs/cosmos-sdk v0.50.9-0.20240904140803-b4127ecb5410 ) diff --git a/indexer/kv_indexer.go b/indexer/kv_indexer.go index 7849418021..be72ca878d 100644 --- a/indexer/kv_indexer.go +++ b/indexer/kv_indexer.go @@ -61,8 +61,20 @@ func NewKVIndexer(db dbm.DB, logger log.Logger, clientCtx client.Context) *KVInd // - Parses eth Tx infos from cosmos-sdk events for every TxResult // - Iterates over all the messages of the Tx // - Builds and stores a indexer.TxResult based on parsed events for every message -func (kv *KVIndexer) IndexBlock(block *tmtypes.Block, txResults []*abci.ExecTxResult) error { - height := block.Height +func (kv *KVIndexer) IndexBlock(block *tmtypes.Block, txResults []*abci.ExecTxResult) (err error) { + defer func(err *error) { + if e := recover(); e != nil { + kv.logger.Debug("panic during parsing block results", "error", e) + + if ee, ok := e.(error); ok { + *err = ee + } else { + *err = fmt.Errorf("panic during parsing block results: %v", e) + } + } + }(&err) + + kv.logger.Debug("(KVIndexer) IndexBlock", "height", block.Height, "txns:", len(block.Txs)) batch := kv.db.NewBatch() defer batch.Close() @@ -71,13 +83,10 @@ func (kv *KVIndexer) IndexBlock(block *tmtypes.Block, txResults []*abci.ExecTxRe var ethTxIndex int32 for txIndex, tx := range block.Txs { result := txResults[txIndex] - if !rpctypes.TxSuccessOrExceedsBlockGasLimit(result) { - continue - } tx, err := kv.clientCtx.TxConfig.TxDecoder()(tx) if err != nil { - kv.logger.Error("Fail to decode tx", "err", err, "block", height, "txIndex", txIndex) + kv.logger.Error("Fail to decode tx", "err", err, "block", block.Height, "txIndex", txIndex) continue } @@ -87,7 +96,7 @@ func (kv *KVIndexer) IndexBlock(block *tmtypes.Block, txResults []*abci.ExecTxRe txs, err := rpctypes.ParseTxResult(result, tx) if err != nil { - kv.logger.Error("Fail to parse event", "err", err, "block", height, "txIndex", txIndex) + kv.logger.Error("Fail to parse event", "err", err, "block", block.Height, "txIndex", txIndex) continue } @@ -97,21 +106,23 @@ func (kv *KVIndexer) IndexBlock(block *tmtypes.Block, txResults []*abci.ExecTxRe var txHash common.Hash txResult := ethermint.TxResult{ - Height: height, + Height: block.Height, TxIndex: uint32(txIndex), MsgIndex: uint32(msgIndex), EthTxIndex: ethTxIndex, } - if result.Code != abci.CodeTypeOK { + if result.Code != abci.CodeTypeOK && result.Codespace != evmtypes.ModuleName { // exceeds block gas limit scenario, set gas used to gas limit because that's what's charged by ante handler. // some old versions don't emit any events, so workaround here directly. txResult.GasUsed = ethMsg.GetGas() txResult.Failed = true txHash = ethMsg.Hash() } else { + // success or fail due to VM error + parsedTx := txs.GetTxByMsgIndex(msgIndex) if parsedTx == nil { - kv.logger.Error("msg index not found in events", "msgIndex", msgIndex) + kv.logger.Error("msg index not found in results", "msgIndex", msgIndex) continue } if parsedTx.EthTxIndex >= 0 && parsedTx.EthTxIndex != ethTxIndex { @@ -127,7 +138,7 @@ func (kv *KVIndexer) IndexBlock(block *tmtypes.Block, txResults []*abci.ExecTxRe ethTxIndex++ if err := saveTxResult(kv.clientCtx.Codec, batch, txHash, &txResult); err != nil { - return errorsmod.Wrapf(err, "IndexBlock %d", height) + return errorsmod.Wrapf(err, "IndexBlock %d", block.Height) } } } diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index 812df33bdb..7bffe1d523 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -277,7 +277,7 @@ func (b *Backend) EthMsgsFromTendermintBlock( tx, err := b.clientCtx.TxConfig.TxDecoder()(tx) if err != nil { - b.logger.Debug("failed to decode transaction in block", "height", block.Height, "error", err.Error()) + b.logger.Warn("failed to decode transaction in block", "height", block.Height, "error", err.Error()) continue } diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index 2e626e2565..1f34c0927f 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -19,6 +19,7 @@ import ( "fmt" errorsmod "cosmossdk.io/errors" + abci "github.com/cometbft/cometbft/abci/types" tmrpcclient "github.com/cometbft/cometbft/rpc/client" tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -156,7 +157,7 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ } tx, err := b.clientCtx.TxConfig.TxDecoder()(resBlock.Block.Txs[res.TxIndex]) if err != nil { - b.logger.Debug("decoding failed", "error", err.Error()) + b.logger.Warn("decoding failed", "error", err.Error()) return nil, fmt.Errorf("failed to decode tx: %w", err) } ethMsg := tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) @@ -170,7 +171,7 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ cumulativeGasUsed := uint64(0) blockRes, err := b.TendermintBlockResultByNumber(&res.Height) if err != nil { - b.logger.Debug("failed to retrieve block results", "height", res.Height, "error", err.Error()) + b.logger.Warn("failed to retrieve block results", "height", res.Height, "error", err.Error()) return nil, nil } for _, txResult := range blockRes.TxsResults[0:res.TxIndex] { @@ -202,7 +203,7 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ uint64(blockRes.Height), ) if err != nil { - b.logger.Debug("failed to parse logs", "hash", hash, "error", err.Error()) + b.logger.Warn("failed to parse logs", "hash", hash, "error", err.Error()) } if res.EthTxIndex == -1 { @@ -317,6 +318,7 @@ func (b *Backend) GetTxByEthHash(hash common.Hash) (*ethermint.TxResult, error) } // fallback to tendermint tx indexer + b.logger.Warn("fallback to tendermint tx indexer! failed txns will not be available", "tx", hash.Hex()) query := fmt.Sprintf("%s.%s='%s'", evmtypes.TypeMsgEthereumTx, evmtypes.AttributeKeyEthereumTxHash, hash.Hex()) txResult, err := b.queryTendermintTxIndexer(query, func(txs *rpctypes.ParsedTxs) *rpctypes.ParsedTx { return txs.GetTxByHash(hash) @@ -334,6 +336,7 @@ func (b *Backend) GetTxByTxIndex(height int64, index uint) (*ethermint.TxResult, } // fallback to tendermint tx indexer + b.logger.Warn("fallback to tendermint tx indexer! failed txns will not be available", "height", height, "txIndex", index) query := fmt.Sprintf("tx.height=%d AND %s.%s=%d", height, evmtypes.TypeMsgEthereumTx, evmtypes.AttributeKeyTxIndex, index, @@ -353,17 +356,19 @@ func (b *Backend) queryTendermintTxIndexer(query string, txGetter func(*rpctypes if err != nil { return nil, err } + if len(resTxs.Txs) == 0 { return nil, errors.New("ethereum tx not found") } + txResult := resTxs.Txs[0] - if !rpctypes.TxSuccessOrExceedsBlockGasLimit(&txResult.TxResult) { - return nil, errors.New("invalid ethereum tx") - } var tx sdk.Tx - if txResult.TxResult.Code != 0 { - // it's only needed when the tx exceeds block gas limit + if rpctypes.TxSuccessOrExceedsBlockGasLimit(&txResult.TxResult) && + txResult.TxResult.Code != abci.CodeTypeOK && + txResult.TxResult.Codespace != evmtypes.ModuleName { + + // only needed when the tx exceeds block gas limit tx, err = b.clientCtx.TxConfig.TxDecoder()(txResult.Tx) if err != nil { return nil, fmt.Errorf("invalid ethereum tx") @@ -386,7 +391,7 @@ func (b *Backend) GetTransactionByBlockAndIndex(block *tmrpctypes.ResultBlock, i if err == nil { tx, err := b.clientCtx.TxConfig.TxDecoder()(block.Block.Txs[res.TxIndex]) if err != nil { - b.logger.Debug("invalid ethereum tx", "height", block.Block.Header, "index", idx) + b.logger.Warn("invalid ethereum tx", "height", block.Block.Header, "index", idx) return nil, nil } @@ -394,14 +399,14 @@ func (b *Backend) GetTransactionByBlockAndIndex(block *tmrpctypes.ResultBlock, i // msgIndex is inferred from tx events, should be within bound. msg, ok = tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) if !ok { - b.logger.Debug("invalid ethereum tx", "height", block.Block.Header, "index", idx) + b.logger.Warn("invalid ethereum tx", "height", block.Block.Header, "index", idx) return nil, nil } } else { i := int(idx) ethMsgs := b.EthMsgsFromTendermintBlock(block, blockRes) if i >= len(ethMsgs) { - b.logger.Debug("block txs index out of bound", "index", i) + b.logger.Warn("block txs index out of bound", "index", i) return nil, nil } diff --git a/rpc/namespaces/ethereum/eth/api.go b/rpc/namespaces/ethereum/eth/api.go index df9c8577a3..6f61b31325 100644 --- a/rpc/namespaces/ethereum/eth/api.go +++ b/rpc/namespaces/ethereum/eth/api.go @@ -457,7 +457,7 @@ func (e *PublicAPI) GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, err uint64(resBlockResult.Height), ) if err != nil { - e.logger.Debug("failed to parse tx logs", "error", err.Error()) + e.logger.Warn("failed to parse tx logs", "error", err.Error()) return nil, nil } diff --git a/rpc/types/events.go b/rpc/types/parsed_tx.go similarity index 60% rename from rpc/types/events.go rename to rpc/types/parsed_tx.go index a0ce40a56a..71898708d9 100644 --- a/rpc/types/events.go +++ b/rpc/types/parsed_tx.go @@ -16,9 +16,13 @@ package types import ( + "encoding/json" + "errors" "fmt" + "regexp" "strconv" + errorsmod "cosmossdk.io/errors" abci "github.com/cometbft/cometbft/abci/types" tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -27,56 +31,24 @@ import ( evmtypes "github.com/evmos/ethermint/x/evm/types" ) -// EventFormat is the format version of the events. -// -// To fix the issue of tx exceeds block gas limit, we changed the event format in a breaking way. -// But to avoid forcing clients to re-sync from scatch, we make json-rpc logic to be compatible with both formats. -type EventFormat int - -const ( - eventFormatUnknown EventFormat = iota - - // Event Format 1 (the format used before PR #1062): - // ``` - // ethereum_tx(amount, ethereumTxHash, [txIndex, txGasUsed], txHash, [receipient], ethereumTxFailed) - // tx_log(txLog, txLog, ...) - // ethereum_tx(amount, ethereumTxHash, [txIndex, txGasUsed], txHash, [receipient], ethereumTxFailed) - // tx_log(txLog, txLog, ...) - // ... - // ``` - eventFormat1 - - // Event Format 2 (the format used after PR #1062): - // ``` - // ethereum_tx(ethereumTxHash, txIndex) - // ethereum_tx(ethereumTxHash, txIndex) - // ... - // ethereum_tx(amount, ethereumTxHash, txIndex, txGasUsed, txHash, [receipient], ethereumTxFailed) - // tx_log(txLog, txLog, ...) - // ethereum_tx(amount, ethereumTxHash, txIndex, txGasUsed, txHash, [receipient], ethereumTxFailed) - // tx_log(txLog, txLog, ...) - // ... - // ``` - // If the transaction exceeds block gas limit, it only emits the first part. - eventFormat2 -) - -// ParsedTx is the tx infos parsed from events. +// ParsedTx is the tx infos parsed from events (success) or log field (failure). type ParsedTx struct { MsgIndex int - // the following fields are parsed from events - - Hash common.Hash - // -1 means uninitialized + Hash common.Hash EthTxIndex int32 GasUsed uint64 Failed bool } +const EthTxIndexUnitialized int32 = -1 + // NewParsedTx initialize a ParsedTx func NewParsedTx(msgIndex int) ParsedTx { - return ParsedTx{MsgIndex: msgIndex, EthTxIndex: -1} + return ParsedTx{ + MsgIndex: msgIndex, + EthTxIndex: EthTxIndexUnitialized, + } } // ParsedTxs is the tx infos parsed from eth tx events. @@ -87,67 +59,50 @@ type ParsedTxs struct { TxHashes map[common.Hash]int } -// ParseTxResult parse eth tx infos from cosmos-sdk events. -// It supports two event formats, the formats are described in the comments of the format constants. +// ParseTxResult parse eth tx infos from ABCI TxResult. +// Uses info from events (success) or log field (failure). func ParseTxResult(result *abci.ExecTxResult, tx sdk.Tx) (*ParsedTxs, error) { - format := eventFormatUnknown - // the index of current ethereum_tx event in format 1 or the second part of format 2 - eventIndex := -1 - p := &ParsedTxs{ TxHashes: make(map[common.Hash]int), } + for _, event := range result.Events { if event.Type != evmtypes.EventTypeEthereumTx { continue } - if format == eventFormatUnknown { - // discover the format version by inspect the first ethereum_tx event. - if len(event.Attributes) > 2 { - format = eventFormat1 - } else { - format = eventFormat2 - } + if err := p.parseTxFromEvent(event.Attributes); err != nil { + return nil, err } + } - if len(event.Attributes) == 2 { - // the first part of format 2 - if err := p.newTx(event.Attributes); err != nil { - return nil, err - } - } else { - // format 1 or second part of format 2 - eventIndex++ - if format == eventFormat1 { - // append tx - if err := p.newTx(event.Attributes); err != nil { - return nil, err - } - } else { - // the second part of format 2, update tx fields - if err := p.updateTx(eventIndex, event.Attributes); err != nil { - return nil, err - } - } + if result.Code != abci.CodeTypeOK && result.Codespace == evmtypes.ModuleName { + for i := 0; i < len(p.Txs); i++ { + // fail all evm txns in the tx result + p.Txs[i].Failed = true } - } - // some old versions miss some events, fill it with tx result - if len(p.Txs) == 1 { - p.Txs[0].GasUsed = uint64(result.GasUsed) + if err := p.parseFromLog(result.Log); err != nil { + return nil, err + } + + return p, nil } - // this could only happen if tx exceeds block gas limit - if result.Code != 0 && tx != nil { + // if namespace is not evm, assume block gas limit is reached + // + // TODO: proper code matching + if result.Code != abci.CodeTypeOK && result.Codespace != evmtypes.ModuleName && tx != nil { for i := 0; i < len(p.Txs); i++ { p.Txs[i].Failed = true - // replace gasUsed with gasLimit because that's what's actually deducted. + // + // TODO: check if this is still correct gasLimit := tx.GetMsgs()[i].(*evmtypes.MsgEthereumTx).GetGas() p.Txs[i].GasUsed = gasLimit } } + return p, nil } @@ -174,33 +129,64 @@ func ParseTxIndexerResult(txResult *tmrpctypes.ResultTx, tx sdk.Tx, getter func( }, nil } -// newTx parse a new tx from events, called during parsing. -func (p *ParsedTxs) newTx(attrs []abci.EventAttribute) error { +// parseTxFromEvent parses a new tx from event attrs. +func (p *ParsedTxs) parseTxFromEvent(attrs []abci.EventAttribute) error { msgIndex := len(p.Txs) tx := NewParsedTx(msgIndex) + if err := fillTxAttributes(&tx, attrs); err != nil { return err } + p.Txs = append(p.Txs, tx) p.TxHashes[tx.Hash] = msgIndex return nil } -// updateTx updates an exiting tx from events, called during parsing. -// In event format 2, we update the tx with the attributes of the second `ethereum_tx` event, -// Due to bug https://github.com/evmos/ethermint/issues/1175, the first `ethereum_tx` event may emit incorrect tx hash, -// so we prefer the second event and override the first one. -func (p *ParsedTxs) updateTx(eventIndex int, attrs []abci.EventAttribute) error { - tx := NewParsedTx(eventIndex) - if err := fillTxAttributes(&tx, attrs); err != nil { +type abciLogVmError struct { + Hash string `json:"tx_hash"` + GasUsed uint64 `json:"gas_used"` + Reason string `json:"reason,omitempty"` + VmError string `json:"vm_error"` + Ret []byte `json:"ret,omitempty"` +} + +// ugly hacks ahead... thanks to errors.Wrapf in BaseApp +var msgErrJSONRx = regexp.MustCompile(`failed to execute message; message index: (\d+): (.*)`) + +// newTx parse a new tx from events, called during parsing. +func (p *ParsedTxs) parseFromLog(logText string) error { + var vmErr abciLogVmError + + parts := msgErrJSONRx.FindStringSubmatch(logText) + if len(parts) != 3 { + return errors.New("failed to locate message error in abci log") + } + + // parts[0] is the whole match + msgIndexStr := parts[1] + msgIndex, err := strconv.Atoi(msgIndexStr) + if err != nil { + return errorsmod.Wrap(err, "failed to parse message index as int") + } + + logJSON := parts[2] + if err := json.Unmarshal([]byte(logJSON), &vmErr); err != nil { + err = errorsmod.Wrap(err, "failed to parse abci log as JSON") return err } - if tx.Hash != p.Txs[eventIndex].Hash { - // if hash is different, index the new one too - p.TxHashes[tx.Hash] = eventIndex + + txHash := common.HexToHash(vmErr.Hash) + parsedTx := ParsedTx{ + MsgIndex: msgIndex, + Hash: txHash, + EthTxIndex: EthTxIndexUnitialized, + GasUsed: vmErr.GasUsed, + Failed: true, } - // override the tx because the second event is more trustworthy - p.Txs[eventIndex] = tx + + p.Txs = append(p.Txs, parsedTx) + p.TxHashes[txHash] = msgIndex return nil } diff --git a/rpc/types/events_test.go b/rpc/types/parsed_tx_test.go similarity index 50% rename from rpc/types/events_test.go rename to rpc/types/parsed_tx_test.go index 13bbccfb83..a6c8341a1a 100644 --- a/rpc/types/events_test.go +++ b/rpc/types/parsed_tx_test.go @@ -13,7 +13,6 @@ import ( func TestParseTxResult(t *testing.T) { address := "0x57f96e6B86CdeFdB3d412547816a82E3E0EbF9D2" txHash := common.BigToHash(big.NewInt(1)) - txHash2 := common.BigToHash(big.NewInt(2)) testCases := []struct { name string @@ -21,62 +20,7 @@ func TestParseTxResult(t *testing.T) { expTxs []*ParsedTx // expected parse result, nil means expect error. }{ { - "format 1 events", - abci.ExecTxResult{ - GasUsed: 21000, - Events: []abci.Event{ - {Type: "coin_received", Attributes: []abci.EventAttribute{ - {Key: "receiver", Value: "ethm12luku6uxehhak02py4rcz65zu0swh7wjun6msa"}, - {Key: "amount", Value: "1252860basetcro"}, - }}, - {Type: "coin_spent", Attributes: []abci.EventAttribute{ - {Key: "spender", Value: "ethm17xpfvakm2amg962yls6f84z3kell8c5lthdzgl"}, - {Key: "amount", Value: "1252860basetcro"}, - }}, - {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ - {Key: "ethereumTxHash", Value: txHash.Hex()}, - {Key: "txIndex", Value: "10"}, - {Key: "amount", Value: "1000"}, - {Key: "txGasUsed", Value: "21000"}, - {Key: "txHash", Value: "14A84ED06282645EFBF080E0B7ED80D8D8D6A36337668A12B5F229F81CDD3F57"}, - {Key: "recipient", Value: "0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7"}, - }}, - {Type: "message", Attributes: []abci.EventAttribute{ - {Key: "action", Value: "/ethermint.evm.v1.MsgEthereumTx"}, - {Key: "key", Value: "ethm17xpfvakm2amg962yls6f84z3kell8c5lthdzgl"}, - {Key: "module", Value: "evm"}, - {Key: "sender", Value: address}, - }}, - {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ - {Key: "ethereumTxHash", Value: txHash2.Hex()}, - {Key: "txIndex", Value: "11"}, - {Key: "amount", Value: "1000"}, - {Key: "txGasUsed", Value: "21000"}, - {Key: "txHash", Value: "14A84ED06282645EFBF080E0B7ED80D8D8D6A36337668A12B5F229F81CDD3F57"}, - {Key: "recipient", Value: "0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7"}, - {Key: "ethereumTxFailed", Value: "contract reverted"}, - }}, - }, - }, - []*ParsedTx{ - { - MsgIndex: 0, - Hash: txHash, - EthTxIndex: 10, - GasUsed: 21000, - Failed: false, - }, - { - MsgIndex: 1, - Hash: txHash2, - EthTxIndex: 11, - GasUsed: 21000, - Failed: true, - }, - }, - }, - { - "format 2 events", + "from events, success", abci.ExecTxResult{ GasUsed: 21000, Events: []abci.Event{ @@ -119,94 +63,80 @@ func TestParseTxResult(t *testing.T) { }, }, { - "format 1 events, failed", + "from events, failed", abci.ExecTxResult{ GasUsed: 21000, Events: []abci.Event{ {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ {Key: "ethereumTxHash", Value: txHash.Hex()}, - {Key: "txIndex", Value: "10"}, - {Key: "amount", Value: "1000"}, - {Key: "txGasUsed", Value: "21000"}, - {Key: "txHash", Value: "14A84ED06282645EFBF080E0B7ED80D8D8D6A36337668A12B5F229F81CDD3F57"}, - {Key: "recipient", Value: "0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7"}, + {Key: "txIndex", Value: "0x01"}, }}, {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ - {Key: "ethereumTxHash", Value: txHash2.Hex()}, - {Key: "txIndex", Value: "0x01"}, {Key: "amount", Value: "1000"}, {Key: "txGasUsed", Value: "21000"}, {Key: "txHash", Value: "14A84ED06282645EFBF080E0B7ED80D8D8D6A36337668A12B5F229F81CDD3F57"}, {Key: "recipient", Value: "0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7"}, - {Key: "ethereumTxFailed", Value: "contract reverted"}, }}, }, }, nil, }, { - "format 1 events, failed", + "from events (hex nums), failed", abci.ExecTxResult{ GasUsed: 21000, Events: []abci.Event{ {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ {Key: "ethereumTxHash", Value: txHash.Hex()}, {Key: "txIndex", Value: "10"}, - {Key: "amount", Value: "1000"}, - {Key: "txGasUsed", Value: "21000"}, - {Key: "txHash", Value: "14A84ED06282645EFBF080E0B7ED80D8D8D6A36337668A12B5F229F81CDD3F57"}, - {Key: "recipient", Value: "0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7"}, }}, {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ - {Key: "ethereumTxHash", Value: txHash2.Hex()}, - {Key: "txIndex", Value: "10"}, {Key: "amount", Value: "1000"}, {Key: "txGasUsed", Value: "0x01"}, {Key: "txHash", Value: "14A84ED06282645EFBF080E0B7ED80D8D8D6A36337668A12B5F229F81CDD3F57"}, {Key: "recipient", Value: "0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7"}, - {Key: "ethereumTxFailed", Value: "contract reverted"}, }}, }, }, nil, }, { - "format 2 events failed", + "from log field, vm execution failed", abci.ExecTxResult{ - GasUsed: 21000, - Events: []abci.Event{ - {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ - {Key: "ethereumTxHash", Value: txHash.Hex()}, - {Key: "txIndex", Value: "0x01"}, - }}, - {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ - {Key: "amount", Value: "1000"}, - {Key: "txGasUsed", Value: "21000"}, - {Key: "txHash", Value: "14A84ED06282645EFBF080E0B7ED80D8D8D6A36337668A12B5F229F81CDD3F57"}, - {Key: "recipient", Value: "0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7"}, - }}, + Code: 15, + Codespace: evmtypes.ModuleName, + GasUsed: 120000, + Events: []abci.Event{}, + Log: "failed to execute message; message index: 0: {\"tx_hash\":\"0x650d5204b07e83b00f489698ea55dd8259cbef658ca95723d1929a985fba8639\",\"gas_used\":120000,\"vm_error\":\"contract creation code storage out of gas\"}", + }, + []*ParsedTx{ + { + MsgIndex: 0, + Hash: common.HexToHash("0x650d5204b07e83b00f489698ea55dd8259cbef658ca95723d1929a985fba8639"), + EthTxIndex: EthTxIndexUnitialized, + GasUsed: 120000, + Failed: true, }, }, - nil, }, { - "format 2 events failed", + "from log field, vm execution reverted", abci.ExecTxResult{ - GasUsed: 21000, - Events: []abci.Event{ - {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ - {Key: "ethereumTxHash", Value: txHash.Hex()}, - {Key: "txIndex", Value: "10"}, - }}, - {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ - {Key: "amount", Value: "1000"}, - {Key: "txGasUsed", Value: "0x01"}, - {Key: "txHash", Value: "14A84ED06282645EFBF080E0B7ED80D8D8D6A36337668A12B5F229F81CDD3F57"}, - {Key: "recipient", Value: "0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7"}, - }}, + Code: 3, + Codespace: evmtypes.ModuleName, + GasUsed: 60000, + Events: []abci.Event{}, + Log: "failed to execute message; message index: 0: {\"tx_hash\":\"0x8d8997cf065cbc6dd44a6c64645633e78bcc51534cc4c11dad1e059318134cc7\",\"gas_used\":60000,\"reason\":\"user requested a revert; see event for details\",\"vm_error\":\"execution reverted\",\"ret\":\"CMN5oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC51c2VyIHJlcXVlc3RlZCBhIHJldmVydDsgc2VlIGV2ZW50IGZvciBkZXRhaWxzAAAAAAAAAAAAAAAAAAAAAAAA\"}", + }, + []*ParsedTx{ + { + MsgIndex: 0, + Hash: common.HexToHash("0x8d8997cf065cbc6dd44a6c64645633e78bcc51534cc4c11dad1e059318134cc7"), + EthTxIndex: EthTxIndexUnitialized, + GasUsed: 60000, + Failed: true, }, }, - nil, }, } diff --git a/server/config/config.go b/server/config/config.go index 8e9167719b..44f548e3a3 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -292,7 +292,7 @@ func DefaultJSONRPCConfig() *JSONRPCConfig { HTTPIdleTimeout: DefaultHTTPIdleTimeout, AllowUnprotectedTxs: DefaultAllowUnprotectedTxs, MaxOpenConnections: DefaultMaxOpenConnections, - EnableIndexer: false, + EnableIndexer: true, AllowIndexerGap: true, MetricsAddress: DefaultJSONRPCMetricsAddress, FixRevertGasRefundHeight: DefaultFixRevertGasRefundHeight, diff --git a/server/indexer_cmd.go b/server/indexer_cmd.go index 5aebd5c121..b9379def1c 100644 --- a/server/indexer_cmd.go +++ b/server/indexer_cmd.go @@ -89,7 +89,6 @@ func NewIndexTxCmd() *cobra.Command { if err := idxer.IndexBlock(blk, resBlk.TxResults); err != nil { return err } - fmt.Println(height) return nil } diff --git a/server/start.go b/server/start.go index e1a5854ac6..606b46e231 100644 --- a/server/start.go +++ b/server/start.go @@ -215,7 +215,7 @@ which accepts a path for the resulting pprof file. cmd.Flags().Int32(srvflags.JSONRPCLogsCap, config.DefaultLogsCap, "Sets the max number of results can be returned from single `eth_getLogs` query") cmd.Flags().Int32(srvflags.JSONRPCBlockRangeCap, config.DefaultBlockRangeCap, "Sets the max block range allowed for `eth_getLogs` query") cmd.Flags().Int(srvflags.JSONRPCMaxOpenConnections, config.DefaultMaxOpenConnections, "Sets the maximum number of simultaneous connections for the server listener") //nolint:lll - cmd.Flags().Bool(srvflags.JSONRPCEnableIndexer, false, "Enable the custom tx indexer for json-rpc") + cmd.Flags().Bool(srvflags.JSONRPCEnableIndexer, true, "Enable the custom tx indexer for json-rpc") cmd.Flags().Bool(srvflags.JSONRPCAllowIndexerGap, true, "Allow block gap for the custom tx indexer for json-rpc") cmd.Flags().Bool(srvflags.JSONRPCEnableMetrics, false, "Define if EVM rpc metrics server should be enabled") diff --git a/testutil/tx/eth.go b/testutil/tx/eth.go index 0827eb1e49..4d213f6184 100644 --- a/testutil/tx/eth.go +++ b/testutil/tx/eth.go @@ -10,7 +10,7 @@ import ( "github.com/evmos/ethermint/x/evm/types" ) -func CreateContractMsgTx( +func CreateUnderpricedContractMsgTx( nonce uint64, signer ethtypes.Signer, gasPrice *big.Int, @@ -31,3 +31,47 @@ func CreateContractMsgTx( return ethMsg, ethMsg.Sign(signer, keyringSigner) } + +func CreateRevertingContractMsgTx( + nonce uint64, + signer ethtypes.Signer, + gasPrice *big.Int, + from common.Address, + keyringSigner keyring.Signer, +) (*types.MsgEthereumTx, error) { + contractCreateTx := ðtypes.AccessListTx{ + GasPrice: gasPrice, + Gas: params.TxGasContractCreation + 136, // accurate accounting, since test cannot refund + To: nil, + Data: common.Hex2Bytes("deadbeef"), + Nonce: nonce, + } + ethTx := ethtypes.NewTx(contractCreateTx) + ethMsg := &types.MsgEthereumTx{} + ethMsg.FromEthereumTx(ethTx) + ethMsg.From = from.Bytes() + + return ethMsg, ethMsg.Sign(signer, keyringSigner) +} + +func CreateNoCodeCallMsgTx( + nonce uint64, + signer ethtypes.Signer, + gasPrice *big.Int, + from common.Address, + keyringSigner keyring.Signer, +) (*types.MsgEthereumTx, error) { + contractCreateTx := ðtypes.AccessListTx{ + GasPrice: gasPrice, + Gas: params.TxGas + params.TxDataNonZeroGasEIP2028*4, // accurate accounting, since test cannot refund + To: &common.Address{}, // no code exists - considered EOA + Data: common.Hex2Bytes("deadbeef"), // 4byte selector + Nonce: nonce, + } + ethTx := ethtypes.NewTx(contractCreateTx) + ethMsg := &types.MsgEthereumTx{} + ethMsg.FromEthereumTx(ethTx) + ethMsg.From = from.Bytes() + + return ethMsg, ethMsg.Sign(signer, keyringSigner) +} diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index cb23aad6fc..3eae28134c 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -29,6 +29,8 @@ import ( sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" "github.com/hashicorp/go-metrics" "github.com/evmos/ethermint/x/evm/types" @@ -123,9 +125,31 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t ), }) + if response.Failed() { + msgErr := types.NewVmErrorWithRet( + response.VmError, + response.Ret, + response.Hash, + response.GasUsed, + ) + + return response, msgErr + } + return response, nil } +func unpackRevertReason(ret []byte) (string, bool) { + retBytes := common.CopyBytes(ret) + + reason, errUnpack := abi.UnpackRevert(retBytes) + if errUnpack == nil { + return reason, true + } + + return "", false +} + // UpdateParams implements the gRPC MsgServer interface. When an UpdateParams // proposal passes, it updates the module parameters. The update can only be // performed if the requested authority is the Cosmos SDK governance module diff --git a/x/evm/keeper/msg_server_test.go b/x/evm/keeper/msg_server_test.go index a835e3c359..391e8dabae 100644 --- a/x/evm/keeper/msg_server_test.go +++ b/x/evm/keeper/msg_server_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "errors" "math/big" "testing" @@ -9,7 +10,6 @@ import ( "github.com/stretchr/testify/suite" ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/params" "github.com/evmos/ethermint/testutil" utiltx "github.com/evmos/ethermint/testutil/tx" "github.com/evmos/ethermint/x/evm/statedb" @@ -36,12 +36,12 @@ func (suite *MsgServerTestSuite) TestEthereumTx() { testCases := []struct { name string malleate func() - expErr bool + expErr error }{ { "Deploy contract tx - insufficient gas", func() { - msg, err = utiltx.CreateContractMsgTx( + msg, err = utiltx.CreateUnderpricedContractMsgTx( vmdb.GetNonce(suite.Address), signer, big.NewInt(1), @@ -50,7 +50,37 @@ func (suite *MsgServerTestSuite) TestEthereumTx() { ) suite.Require().NoError(err) }, - true, + errors.New("intrinsic gas too low"), + }, + { + "Deploy contract tx - vm revert", + func() { + msg, err = utiltx.CreateRevertingContractMsgTx( + vmdb.GetNonce(suite.Address), + signer, + big.NewInt(1), + suite.Address, + suite.Signer, + ) + suite.Require().NoError(err) + expectedGasUsed = msg.GetGas() + }, + errors.New("invalid opcode: opcode 0xde not defined"), + }, + { + "Call no code tx - success", + func() { + msg, err = utiltx.CreateNoCodeCallMsgTx( + vmdb.GetNonce(suite.Address), + signer, + big.NewInt(1), + suite.Address, + suite.Signer, + ) + suite.Require().NoError(err) + expectedGasUsed = msg.GetGas() + }, + nil, }, { "Transfer funds tx", @@ -65,9 +95,9 @@ func (suite *MsgServerTestSuite) TestEthereumTx() { nil, ) suite.Require().NoError(err) - expectedGasUsed = params.TxGas + expectedGasUsed = msg.GetGas() }, - false, + nil, }, } @@ -79,8 +109,8 @@ func (suite *MsgServerTestSuite) TestEthereumTx() { tc.malleate() res, err := suite.App.EvmKeeper.EthereumTx(suite.Ctx, msg) - if tc.expErr { - suite.Require().Error(err) + if tc.expErr != nil { + suite.Require().ErrorContains(err, tc.expErr.Error()) return } suite.Require().NoError(err) diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index 8ddff9f54a..311ab6e5c9 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -218,6 +218,7 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, msgEth *types.MsgEthereumTx) if !res.Failed() { receipt.Status = ethtypes.ReceiptStatusSuccessful + // Only call hooks if tx executed successfully. if err = k.PostTxProcessing(tmpCtx, msg, receipt); err != nil { // If hooks return error, revert the whole tx. @@ -232,6 +233,8 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, msgEth *types.MsgEthereumTx) // Since the post-processing can alter the log, we need to update the result res.Logs = types.NewLogsFromEth(receipt.Logs) } + } else { + receipt.Status = ethtypes.ReceiptStatusFailed } // refund gas in order to match the Ethereum gas consumption instead of the default SDK one. diff --git a/x/evm/keeper/state_transition_test.go b/x/evm/keeper/state_transition_test.go index bdc95a1f87..3fd99d5356 100644 --- a/x/evm/keeper/state_transition_test.go +++ b/x/evm/keeper/state_transition_test.go @@ -465,7 +465,7 @@ func (suite *StateTransitionTestSuite) TestRefundGas() { noError: false, expGasRefund: params.TxGas, malleate: func() { - m, err = suite.createContractGethMsg( + m, err = suite.createUnderpricedContractGethMsg( suite.StateDB().GetNonce(suite.Address), ethtypes.LatestSignerForChainID(suite.App.EvmKeeper.ChainID()), big.NewInt(-100), @@ -695,11 +695,11 @@ func (suite *StateTransitionTestSuite) TestApplyMessageWithConfig() { { "create contract tx with config param EnableCreate = false", func() { - msg, err = suite.createContractGethMsg(vmdb.GetNonce(suite.Address), signer, big.NewInt(1)) + msg, err = suite.createUnderpricedContractGethMsg(vmdb.GetNonce(suite.Address), signer, big.NewInt(1)) suite.Require().NoError(err) config.Params.EnableCreate = false }, - true, + true, // NOTE(max): this checks for the wrong error; TODO: error matcing }, } @@ -732,8 +732,8 @@ func (suite *StateTransitionTestSuite) TestApplyMessageWithConfig() { } } -func (suite *StateTransitionTestSuite) createContractGethMsg(nonce uint64, signer ethtypes.Signer, gasPrice *big.Int) (*core.Message, error) { - ethMsg, err := utiltx.CreateContractMsgTx(nonce, signer, gasPrice, suite.Address, suite.Signer) +func (suite *StateTransitionTestSuite) createUnderpricedContractGethMsg(nonce uint64, signer ethtypes.Signer, gasPrice *big.Int) (*core.Message, error) { + ethMsg, err := utiltx.CreateUnderpricedContractMsgTx(nonce, signer, gasPrice, suite.Address, suite.Signer) if err != nil { return nil, err } diff --git a/x/evm/types/errors.go b/x/evm/types/errors.go index 87179c50f6..1ab26e2065 100644 --- a/x/evm/types/errors.go +++ b/x/evm/types/errors.go @@ -16,6 +16,7 @@ package types import ( + "encoding/json" "errors" "fmt" @@ -118,15 +119,160 @@ var ( ErrInvalidGasLimit = errorsmod.Register(ModuleName, codeErrInvalidGasLimit, "invalid gas limit") ) +// VmError is an interface that represents a reverted or failed EVM execution. +// The Ret() method returns the revert reason bytes associated with the error, if any. +// The Cause() method returns the unwrapped error. For ABCIInfo integration. +type VmError interface { + String() string + Cause() error + Error() string + VmError() string + Ret() []byte +} + +type vmErrorWithRet struct { + cause error + vmErr string + ret []byte + hash string + gasUsed uint64 + + // derived data + + err error + reason string +} + +// Ret returns the revert reason bytes associated with the VmError. +func (e *vmErrorWithRet) Ret() []byte { + if e == nil { + return nil + } + + return e.ret +} + +// VmError returns the VM error string associated with the VmError. +func (e *vmErrorWithRet) VmError() string { + if e == nil { + return "" + } + + return e.vmErr +} + +// Reason returns the reason string associated with the VmError. +func (e *vmErrorWithRet) Reason() string { + if e == nil { + return "" + } + + return e.reason +} + +// Cause returns the module-level error that can be used for ABCIInfo integration. +func (e *vmErrorWithRet) Cause() error { + if e == nil { + return nil + } + + return e.cause +} + +type abciLogVmError struct { + Hash string `json:"tx_hash"` + GasUsed uint64 `json:"gas_used"` + Reason string `json:"reason,omitempty"` + VmError string `json:"vm_error"` + Ret []byte `json:"ret,omitempty"` +} + +// String returns a human-readable string of the error. Includes revert reason if available. +func (e *vmErrorWithRet) String() string { + if e == nil || e.err == nil { + return "" + } + + return e.err.Error() +} + +// Error returns a JSON-encoded string representation of the VmErrorWithRet. +// This includes the transaction hash, gas used, revert reason (if available), +// and the VM error that occurred. For integration with ABCIInfo. +func (e *vmErrorWithRet) Error() string { + if e == nil { + return "" + } + + return e.toJSON() +} + +func (e *vmErrorWithRet) toJSON() string { + logData := &abciLogVmError{ + Hash: e.hash, + GasUsed: e.gasUsed, + Reason: e.reason, + VmError: e.vmErr, + Ret: e.ret, + } + + logStr, marshalError := json.Marshal(logData) + if marshalError != nil { + // fallback to the original error as text + // we cannot handle error in this flow, nor panic + return e.err.Error() + } + + return string(logStr) +} + +// NewVmErrorWithRet creates a new VmError augmented with the revert reason bytes. +// cause is the module-level error that can be used for ABCIInfo integration. +// vmErr is the VM error string associated with the VmError. +// ret is the revert reason bytes associated with the VmError (only if the VM error is ErrExecutionReverted). +func NewVmErrorWithRet( + vmErr string, + ret []byte, + hash string, + gasUsed uint64, +) VmError { + e := &vmErrorWithRet{ + vmErr: vmErr, + hash: hash, + gasUsed: gasUsed, + } + + if e.vmErr == vm.ErrExecutionReverted.Error() { + e.err = vm.ErrExecutionReverted + + // store only if the VM error is ErrExecutionReverted + e.ret = common.CopyBytes(ret) + + reason, errUnpack := abi.UnpackRevert(e.ret) + if errUnpack == nil { + e.err = fmt.Errorf("%s: %s", e.err.Error(), reason) + e.reason = reason + e.cause = errorsmod.Wrap(ErrExecutionReverted, e.toJSON()) + } + } else { + e.err = errors.New(e.vmErr) + e.cause = errorsmod.Wrap(ErrVMExecution, e.toJSON()) + } + + return e +} + // NewExecErrorWithReason unpacks the revert return bytes and returns a wrapped error // with the return reason. func NewExecErrorWithReason(revertReason []byte) *RevertError { result := common.CopyBytes(revertReason) reason, errUnpack := abi.UnpackRevert(result) - err := errors.New("execution reverted") + + err := vm.ErrExecutionReverted if errUnpack == nil { - err = fmt.Errorf("execution reverted: %v", reason) + err = fmt.Errorf("%s: %v", err.Error(), reason) } + return &RevertError{ error: err, reason: hexutil.Encode(result), diff --git a/x/evm/types/utils.go b/x/evm/types/utils.go index f4260335b0..472aebb1f5 100644 --- a/x/evm/types/utils.go +++ b/x/evm/types/utils.go @@ -110,13 +110,16 @@ func DecodeMsgLogsFromEvents(in []byte, events []abci.Event, msgIndex int, block if err != nil { return nil, err } + var logs []*ethtypes.Log if msgIndex < len(txResponses) { logs = logsFromTxResponse(nil, txResponses[msgIndex], blockNumber) } + if len(logs) == 0 { logs, err = TxLogsFromEvents(events, msgIndex) } + return logs, err } @@ -135,7 +138,8 @@ func TxLogsFromEvents(events []abci.Event, msgIndex int) ([]*ethtypes.Log, error return ParseTxLogsFromEvent(event) } - return nil, fmt.Errorf("eth tx logs not found for message index %d", msgIndex) + + return []*ethtypes.Log{}, nil } // ParseTxLogsFromEvent parse tx logs from one event From dd47b3caff58f5baff4b95cd017f1d9ac2fea3e6 Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 27 Sep 2024 16:50:19 +0200 Subject: [PATCH 2/7] fix: include all txns in eth_getBlock, fixes explorer Also adjust the tests. TODO: implement eth_getBlockReceipts --- go.mod | 1 - rpc/backend/blocks.go | 29 ++++++----------------------- rpc/backend/blocks_test.go | 20 ++++---------------- rpc/backend/tracing.go | 13 ++----------- rpc/backend/tracing_test.go | 2 -- 5 files changed, 12 insertions(+), 53 deletions(-) diff --git a/go.mod b/go.mod index 5ede6d1e46..aeeb988a7c 100644 --- a/go.mod +++ b/go.mod @@ -275,7 +275,6 @@ replace ( cosmossdk.io/client/v2 => github.com/InjectiveLabs/cosmos-sdk/client/v2 v2.0.0-20240904140803-b4127ecb5410 cosmossdk.io/store => github.com/InjectiveLabs/cosmos-sdk/store v0.0.0-20240904140803-b4127ecb5410 cosmossdk.io/x/tx => github.com/InjectiveLabs/cosmos-sdk/x/tx v0.0.0-20240904140803-b4127ecb5410 - cosmossdk.io/errors => ../cosmos-sdk/errors github.com/cosmos/cosmos-sdk => github.com/InjectiveLabs/cosmos-sdk v0.50.9-0.20240904140803-b4127ecb5410 ) diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index 7bffe1d523..73062be7c4 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -254,9 +254,7 @@ func (b *Backend) BlockNumberFromTendermintByHash(blockHash common.Hash) (*big.I return big.NewInt(resBlock.Block.Height), nil } -// EthMsgsFromTendermintBlock returns all real MsgEthereumTxs from a -// Tendermint block. It also ensures consistency over the correct txs indexes -// across RPC endpoints +// EthMsgsFromTendermintBlock returns all real MsgEthereumTxs from a Tendermint block. func (b *Backend) EthMsgsFromTendermintBlock( resBlock *tmrpctypes.ResultBlock, blockRes *tmrpctypes.ResultBlockResults, @@ -264,24 +262,14 @@ func (b *Backend) EthMsgsFromTendermintBlock( var result []*evmtypes.MsgEthereumTx block := resBlock.Block - txResults := blockRes.TxsResults - - for i, tx := range block.Txs { - // Check if tx exists on EVM by cross checking with blockResults: - // - Include unsuccessful tx that exceeds block gas limit - // - Exclude unsuccessful tx with any other error but ExceedBlockGasLimit - if !rpctypes.TxSuccessOrExceedsBlockGasLimit(txResults[i]) { - b.logger.Debug("invalid tx result code", "cosmos-hash", hexutil.Encode(tx.Hash())) - continue - } - - tx, err := b.clientCtx.TxConfig.TxDecoder()(tx) + for _, tx := range block.Txs { + decodedTx, err := b.clientCtx.TxConfig.TxDecoder()(tx) if err != nil { b.logger.Warn("failed to decode transaction in block", "height", block.Height, "error", err.Error()) continue } - for _, msg := range tx.GetMsgs() { + for _, msg := range decodedTx.GetMsgs() { ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { continue @@ -445,14 +433,8 @@ func (b *Backend) RPCBlockFromTendermintBlock( b.logger.Error("failed to query consensus params", "error", err.Error()) } - gasUsed := uint64(0) - + var gasUsed uint64 for _, txsResult := range blockRes.TxsResults { - // workaround for cosmos-sdk bug. https://github.com/cosmos/cosmos-sdk/issues/10832 - if ShouldIgnoreGasUsed(txsResult) { - // block gas limit has exceeded, other txs must have failed with same reason. - break - } gasUsed += uint64(txsResult.GetGasUsed()) } @@ -511,6 +493,7 @@ func (b *Backend) EthBlockFromTendermintBlock( } // TODO: add tx receipts + // TODO(max): check if this still needed ethBlock := ethtypes.NewBlockWithHeader(ethHeader).WithBody(ethtypes.Body{Transactions: txs}) return ethBlock, nil diff --git a/rpc/backend/blocks_test.go b/rpc/backend/blocks_test.go index e6669c84b2..cbb16aeb58 100644 --- a/rpc/backend/blocks_test.go +++ b/rpc/backend/blocks_test.go @@ -984,7 +984,7 @@ func (suite *BackendTestSuite) TestGetEthBlockFromTendermint() { true, }, { - "pass - block with tx - with ShouldIgnoreGasUsed - empty txs", + "pass - block with tx - with ShouldIgnoreGasUsed", sdkmath.NewInt(1).BigInt(), sdk.AccAddress(tests.GenerateAddress().Bytes()), int64(1), @@ -1010,7 +1010,7 @@ func (suite *BackendTestSuite) TestGetEthBlockFromTendermint() { client := suite.backend.clientCtx.Client.(*mocks.Client) RegisterConsensusParams(client, height) }, - false, + true, true, }, { @@ -1127,20 +1127,6 @@ func (suite *BackendTestSuite) TestEthMsgsFromTendermintBlock() { blockRes *tmrpctypes.ResultBlockResults expMsgs []*evmtypes.MsgEthereumTx }{ - { - "tx in not included in block - unsuccessful tx without ExceedBlockGasLimit error", - &tmrpctypes.ResultBlock{ - Block: tmtypes.MakeBlock(1, []tmtypes.Tx{bz}, nil, nil), - }, - &tmrpctypes.ResultBlockResults{ - TxsResults: []*types.ExecTxResult{ - { - Code: 1, - }, - }, - }, - []*evmtypes.MsgEthereumTx(nil), - }, { "tx included in block - unsuccessful tx with ExceedBlockGasLimit error", &tmrpctypes.ResultBlock{ @@ -1171,6 +1157,8 @@ func (suite *BackendTestSuite) TestEthMsgsFromTendermintBlock() { }, []*evmtypes.MsgEthereumTx{msgEthereumTx}, }, + + // TODO(max): include tests for failed vm execution and reverts } for _, tc := range testCases { suite.Run(fmt.Sprintf("Case %s", tc.name), func() { diff --git a/rpc/backend/tracing.go b/rpc/backend/tracing.go index 2b80baba1d..ca97856c3e 100644 --- a/rpc/backend/tracing.go +++ b/rpc/backend/tracing.go @@ -22,7 +22,6 @@ import ( tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" rpctypes "github.com/evmos/ethermint/rpc/types" evmtypes "github.com/evmos/ethermint/x/evm/types" "github.com/pkg/errors" @@ -154,22 +153,14 @@ func (b *Backend) TraceBlock(height rpctypes.BlockNumber, // If there are no transactions return empty array return []*evmtypes.TxTraceResult{}, nil } - blockRes, err := b.TendermintBlockResultByNumber(&block.Block.Height) - if err != nil { - b.logger.Debug("block result not found", "height", block.Block.Height, "error", err.Error()) - return nil, nil - } + txDecoder := b.clientCtx.TxConfig.TxDecoder() var txsMessages []*evmtypes.MsgEthereumTx for i, tx := range txs { - if !rpctypes.TxSuccessOrExceedsBlockGasLimit(blockRes.TxsResults[i]) { - b.logger.Debug("invalid tx result code", "cosmos-hash", hexutil.Encode(tx.Hash())) - continue - } decodedTx, err := txDecoder(tx) if err != nil { - b.logger.Error("failed to decode transaction", "hash", txs[i].Hash(), "error", err.Error()) + b.logger.Warn("failed to decode transaction", "hash", txs[i].Hash(), "error", err.Error()) continue } diff --git a/rpc/backend/tracing_test.go b/rpc/backend/tracing_test.go index 991e9dd316..e306aad865 100644 --- a/rpc/backend/tracing_test.go +++ b/rpc/backend/tracing_test.go @@ -245,8 +245,6 @@ func (suite *BackendTestSuite) TestTraceBlock() { func() { queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) RegisterTraceBlock(queryClient, 1, 9000, []*evmtypes.MsgEthereumTx{msgEthTx}) - client := suite.backend.clientCtx.Client.(*mocks.Client) - RegisterBlockResults(client, 1) }, []*evmtypes.TxTraceResult{}, &resBlockFilled, From 9f09d089af01d4dd07144eee9775570096a9c5ad Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 30 Sep 2024 10:44:59 +0200 Subject: [PATCH 3/7] fix: remove extra event from PatchTxResponses hack --- rpc/types/parsed_tx_test.go | 4 ---- x/evm/types/response.go | 33 ++++++++------------------------- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/rpc/types/parsed_tx_test.go b/rpc/types/parsed_tx_test.go index a6c8341a1a..087b8f1ed5 100644 --- a/rpc/types/parsed_tx_test.go +++ b/rpc/types/parsed_tx_test.go @@ -32,10 +32,6 @@ func TestParseTxResult(t *testing.T) { {Key: "spender", Value: "ethm17xpfvakm2amg962yls6f84z3kell8c5lthdzgl"}, {Key: "amount", Value: "1252860basetcro"}, }}, - {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ - {Key: "ethereumTxHash", Value: txHash.Hex()}, - {Key: "txIndex", Value: "0"}, - }}, {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ {Key: "amount", Value: "1000"}, {Key: "ethereumTxHash", Value: txHash.Hex()}, diff --git a/x/evm/types/response.go b/x/evm/types/response.go index 8166405783..2ad67ce3ad 100644 --- a/x/evm/types/response.go +++ b/x/evm/types/response.go @@ -1,8 +1,6 @@ package types import ( - "strconv" - abci "github.com/cometbft/cometbft/abci/types" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -27,10 +25,10 @@ func PatchTxResponses(input []*abci.ExecTxResult) []*abci.ExecTxResult { } var ( - anteEvents []abci.Event // if the response data is modified and need to be marshaled back dataDirty bool ) + for i, rsp := range txMsgData.MsgResponses { var response MsgEthereumTxResponse if rsp.TypeUrl != "/"+proto.MessageName(&response) { @@ -41,14 +39,6 @@ func PatchTxResponses(input []*abci.ExecTxResult) []*abci.ExecTxResult { panic(err) } - anteEvents = append(anteEvents, abci.Event{ - Type: EventTypeEthereumTx, - Attributes: []abci.EventAttribute{ - {Key: AttributeKeyEthereumTxHash, Value: response.Hash}, - {Key: AttributeKeyTxIndex, Value: strconv.FormatUint(txIndex, 10)}, - }, - }) - if len(response.Logs) > 0 { for _, log := range response.Logs { log.TxIndex = txIndex @@ -68,22 +58,15 @@ func PatchTxResponses(input []*abci.ExecTxResult) []*abci.ExecTxResult { txIndex++ } - if len(anteEvents) > 0 { - // prepend ante events in front to emulate the side effect of `EthEmitEventDecorator` - events := make([]abci.Event, len(anteEvents)+len(res.Events)) - copy(events, anteEvents) - copy(events[len(anteEvents):], res.Events) - res.Events = events - - if dataDirty { - data, err := proto.Marshal(&txMsgData) - if err != nil { - panic(err) - } - - res.Data = data + if dataDirty { + data, err := proto.Marshal(&txMsgData) + if err != nil { + panic(err) } + + res.Data = data } } + return input } From 2a74c2d2702b1547087ada7300c7cec45fefb7f6 Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 30 Sep 2024 12:47:09 +0200 Subject: [PATCH 4/7] fix: unit tests were broken --- indexer/kv_indexer_test.go | 37 +++++++++++++------------------------ x/evm/handler_test.go | 13 ++++++++++--- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/indexer/kv_indexer_test.go b/indexer/kv_indexer_test.go index ac0971ca06..868e79d510 100644 --- a/indexer/kv_indexer_test.go +++ b/indexer/kv_indexer_test.go @@ -57,7 +57,7 @@ func TestKVIndexer(t *testing.T) { expSuccess bool }{ { - "success, format 1", + "success", &tmtypes.Block{Header: tmtypes.Header{Height: 1}, Data: tmtypes.Data{Txs: []tmtypes.Tx{txBz}}}, []*abci.ExecTxResult{ { @@ -68,7 +68,7 @@ func TestKVIndexer(t *testing.T) { {Key: "txIndex", Value: "0"}, {Key: "amount", Value: "1000"}, {Key: "txGasUsed", Value: "21000"}, - {Key: "txHash", Value: ""}, + {Key: "txHash", Value: "14A84ED06282645EFBF080E0B7ED80D8D8D6A36337668A12B5F229F81CDD3F57"}, {Key: "recipient", Value: "0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7"}, }}, }, @@ -77,51 +77,40 @@ func TestKVIndexer(t *testing.T) { true, }, { - "success, format 2", + "success, exceed block gas limit", &tmtypes.Block{Header: tmtypes.Header{Height: 1}, Data: tmtypes.Data{Txs: []tmtypes.Tx{txBz}}}, []*abci.ExecTxResult{ { - Code: 0, - Events: []abci.Event{ - {Type: types.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ - {Key: "ethereumTxHash", Value: txHash.Hex()}, - {Key: "txIndex", Value: "0"}, - }}, - {Type: types.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ - {Key: "ethereumTxHash", Value: txHash.Hex()}, - {Key: "amount", Value: "1000"}, - {Key: "txGasUsed", Value: "21000"}, - {Key: "txHash", Value: "14A84ED06282645EFBF080E0B7ED80D8D8D6A36337668A12B5F229F81CDD3F57"}, - {Key: "recipient", Value: "0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7"}, - }}, - }, + Code: 11, + Log: "out of gas in location: block gas meter; gasWanted: 21000", + Events: []abci.Event{}, }, }, true, }, { - "success, exceed block gas limit", + "success, failed eth tx (vm error)", &tmtypes.Block{Header: tmtypes.Header{Height: 1}, Data: tmtypes.Data{Txs: []tmtypes.Tx{txBz}}}, []*abci.ExecTxResult{ { - Code: 11, - Log: "out of gas in location: block gas meter; gasWanted: 21000", + Code: 15, + Log: "failed to execute message; message index: 0: {\"tx_hash\":\"0x650d5204b07e83b00f489698ea55dd8259cbef658ca95723d1929a985fba8639\",\"gas_used\":120000,\"vm_error\":\"contract creation code storage out of gas\"}", Events: []abci.Event{}, }, }, true, }, { - "fail, failed eth tx", + "success, failed eth tx (vm revert)", &tmtypes.Block{Header: tmtypes.Header{Height: 1}, Data: tmtypes.Data{Txs: []tmtypes.Tx{txBz}}}, []*abci.ExecTxResult{ { - Code: 15, - Log: "nonce mismatch", + Code: 3, + Log: "failed to execute message; message index: 0: {\"tx_hash\":\"0x8d8997cf065cbc6dd44a6c64645633e78bcc51534cc4c11dad1e059318134cc7\",\"gas_used\":60000,\"reason\":\"user requested a revert; see event for details\",\"vm_error\":\"execution reverted\",\"ret\":\"CMN5oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC51c2VyIHJlcXVlc3RlZCBhIHJldmVydDsgc2VlIGV2ZW50IGZvciBkZXRhaWxzAAAAAAAAAAAAAAAAAAAAAAAA\"}", Events: []abci.Event{}, }, }, - false, + true, }, { "fail, invalid events", diff --git a/x/evm/handler_test.go b/x/evm/handler_test.go index d361c106e1..7cc5328035 100644 --- a/x/evm/handler_test.go +++ b/x/evm/handler_test.go @@ -17,6 +17,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -54,12 +55,16 @@ func (suite *HandlerTestSuite) SetupTest() { Address: app.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName).String(), Coins: coins, }, + { + Address: sdk.AccAddress(suite.Address.Bytes()).String(), + Coins: coins, + }, } var bankGenesis banktypes.GenesisState app.AppCodec().MustUnmarshalJSON(genesis[banktypes.ModuleName], &bankGenesis) // Update balances and total supply bankGenesis.Balances = append(bankGenesis.Balances, balances...) - bankGenesis.Supply = bankGenesis.Supply.Add(coins...).Add(coins...) + bankGenesis.Supply = bankGenesis.Supply.Add(coins...).Add(coins...).Add(coins...) genesis[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(&bankGenesis) acc := ðermint.EthAccount{ BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(suite.Address.Bytes()), nil, 0, 0), @@ -145,6 +150,7 @@ func (suite *HandlerTestSuite) TestHandleMsgEthereumTx() { if tc.expPass { suite.Require().NoError(err) suite.Require().NotNil(res) + suite.Require().False(res.Failed()) } else { suite.Require().Error(err) suite.Require().Nil(res) @@ -293,6 +299,7 @@ func (suite *HandlerTestSuite) TestSendTransaction() { result, err := suite.App.EvmKeeper.EthereumTx(suite.Ctx, tx) suite.Require().NoError(err) suite.Require().NotNil(result) + suite.Require().False(result.Failed()) } func (suite *HandlerTestSuite) TestOutOfGasWhenDeployContract() { @@ -484,7 +491,7 @@ func (suite *HandlerTestSuite) TestERC20TransferReverted() { suite.Require().NoError(err) res, err := k.EthereumTx(suite.Ctx, tx) - suite.Require().NoError(err) + suite.Require().ErrorContains(err, tc.expErr) suite.Require().True(res.Failed()) suite.Require().Equal(tc.expErr, res.VmError) @@ -557,7 +564,7 @@ func (suite *HandlerTestSuite) TestContractDeploymentRevert() { suite.Require().NoError(db.Commit()) rsp, err := k.EthereumTx(suite.Ctx, tx) - suite.Require().NoError(err) + suite.Require().ErrorContains(err, vm.ErrOutOfGas.Error()) suite.Require().True(rsp.Failed()) // nonce don't change From 20600a146ede0374f36f6ea6c1c92a22f3cb215a Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 30 Sep 2024 12:55:02 +0200 Subject: [PATCH 5/7] chore: simplify workflows --- .github/workflows/build.yml | 8 ---- .github/workflows/deploy-contract.yml | 10 +--- .github/workflows/test.yml | 69 --------------------------- 3 files changed, 1 insertion(+), 86 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 238d7fd3aa..65a63fcb5f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,14 +9,6 @@ concurrency: cancel-in-progress: true jobs: - cleanup-runs: - runs-on: ubuntu-latest - steps: - - uses: rokroskar/workflow-run-cleanup-action@master - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/develop'" - build: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/deploy-contract.yml b/.github/workflows/deploy-contract.yml index bde98337b5..5eb075dfaa 100644 --- a/.github/workflows/deploy-contract.yml +++ b/.github/workflows/deploy-contract.yml @@ -9,14 +9,6 @@ concurrency: cancel-in-progress: true jobs: - cleanup-runs: - runs-on: ubuntu-latest - steps: - - uses: rokroskar/workflow-run-cleanup-action@master - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/develop'" - deploy: runs-on: ubuntu-latest steps: @@ -24,7 +16,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v3 with: - node-version: '12.x' + node-version: "12.x" - name: Install dependencies run: npm install - uses: technote-space/get-diff-action@v6.1.2 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ab418bf56a..9d53f719ab 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,14 +11,6 @@ concurrency: cancel-in-progress: true jobs: - cleanup-runs: - runs-on: ubuntu-latest - steps: - - uses: rokroskar/workflow-run-cleanup-action@master - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/main'" - test-unit-cover: runs-on: ubuntu-latest steps: @@ -87,67 +79,6 @@ jobs: make test-rpc if: env.GIT_DIFF - integration_tests: - runs-on: ubuntu-latest - timeout-minutes: 60 - strategy: - matrix: - tests: [unmarked, upgrade, filter] - env: - TESTS_TO_RUN: ${{ matrix.tests }} - steps: - - uses: actions/checkout@v3 - - uses: cachix/install-nix-action@v26 - with: - nix_path: nixpkgs=channel:nixos-23.11 - extra_nix_config: | - access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} - - uses: cachix/cachix-action@v14 - with: - name: crypto-ethermint - signingKey: "${{ secrets.CACHIX_SIGNING_KEY }}" - - uses: technote-space/get-diff-action@v6.1.2 - with: - PATTERNS: | - **/**.sol - **/**.go - go.mod - go.sum - tests/integration_tests/** - - name: Run integration tests - run: make run-integration-tests - if: env.GIT_DIFF - - name: 'Tar debug files' - if: failure() - run: tar cfz debug_files.tar.gz -C /tmp/pytest-of-runner . - - uses: actions/upload-artifact@v3 - if: failure() - with: - name: debug-files - path: debug_files.tar.gz - if-no-files-found: ignore - - upload-cache: - if: github.event_name == 'push' - needs: ["integration_tests"] - strategy: - matrix: - os: [macos-latest] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v3 - - uses: cachix/install-nix-action@v26 - with: - nix_path: nixpkgs=channel:nixos-23.11 - extra_nix_config: | - access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} - - uses: cachix/cachix-action@v14 - with: - name: crypto-ethermint - signingKey: "${{ secrets.CACHIX_SIGNING_KEY }}" - - name: 'instantiate integration test env' - run: nix-store -r $(nix-instantiate tests/integration_tests/shell.nix) - test-sim-nondeterminism: runs-on: ubuntu-latest timeout-minutes: 120 From fc4975338eb44c4e2d036cd04fc379779afa93ca Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 30 Sep 2024 13:01:41 +0200 Subject: [PATCH 6/7] chore: limit test workflow to have only test-unit-cover --- .github/workflows/test.yml | 122 ------------------------------------- 1 file changed, 122 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9d53f719ab..034aa061ea 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,125 +36,3 @@ jobs: fail_ci_if_error: true token: ${{ secrets.CODECOV_TOKEN }} if: env.GIT_DIFF - - test-importer: - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - uses: actions/setup-go@v4 - with: - go-version: 1.21 - check-latest: true - - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.1.2 - id: git_diff - with: - PATTERNS: | - **/**.go - go.mod - go.sum - - name: test-importer - run: | - make test-import - if: env.GIT_DIFF - - test-rpc: - runs-on: ubuntu-latest - timeout-minutes: 30 - steps: - - uses: actions/setup-go@v4 - with: - go-version: 1.21 - check-latest: true - - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.1.2 - with: - PATTERNS: | - **/**.sol - **/**.go - go.mod - go.sum - - name: Test rpc endpoint - run: | - make test-rpc - if: env.GIT_DIFF - - test-sim-nondeterminism: - runs-on: ubuntu-latest - timeout-minutes: 120 - steps: - - uses: actions/setup-go@v3 - with: - go-version: 1.21 - check-latest: true - - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.1.1 - with: - PATTERNS: | - **/**.go - go.mod - go.sum - - name: Test simulation nondeterminism - run: | - make test-sim-nondeterminism - if: env.GIT_DIFF - - test-sim-random-genesis-fast: - runs-on: ubuntu-latest - timeout-minutes: 120 - steps: - - uses: actions/setup-go@v3 - with: - go-version: 1.21 - check-latest: true - - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.1.1 - with: - PATTERNS: | - **/**.go - go.mod - go.sum - - name: Test simulation with random genesis - run: | - make test-sim-random-genesis-fast - if: env.GIT_DIFF - - test-sim-import-export: - runs-on: ubuntu-latest - timeout-minutes: 120 - steps: - - uses: actions/setup-go@v3 - with: - go-version: 1.21 - check-latest: true - - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.1.1 - with: - PATTERNS: | - **/**.go - go.mod - go.sum - - name: Simulation of import and export genesis - run: | - make test-sim-import-export - if: env.GIT_DIFF - - test-sim-after-import: - runs-on: ubuntu-latest - timeout-minutes: 120 - steps: - - uses: actions/setup-go@v3 - with: - go-version: 1.21 - check-latest: true - - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.1.1 - with: - PATTERNS: | - **/**.go - go.mod - go.sum - - name: Test simulation after import - run: | - make test-sim-after-import - if: env.GIT_DIFF From 7044f2e67e8491e13c632c6eb57a43c201d90d41 Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 30 Sep 2024 13:11:06 +0200 Subject: [PATCH 7/7] chore: disable coverage upload until codecov token is set --- .github/workflows/test.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 034aa061ea..5e33e682f0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,9 +30,3 @@ jobs: run: | make test-unit-cover if: env.GIT_DIFF - - uses: codecov/codecov-action@v4 - with: - file: ./coverage.txt - fail_ci_if_error: true - token: ${{ secrets.CODECOV_TOKEN }} - if: env.GIT_DIFF