Skip to content
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
9 changes: 7 additions & 2 deletions x/vm/keeper/call_evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,9 @@ func (k Keeper) DerivedEVMCallWithData(
sdk.NewAttribute(sdk.AttributeKeyAmount, value.String()),
// add event for ethereum transaction hash format;
sdk.NewAttribute(types.AttributeKeyEthereumTxHash, ethTxHash),
// add event for index of valid ethereum tx; NOTE: default txindex for derivedTx
sdk.NewAttribute(types.AttributeKeyTxIndex, strconv.FormatUint(types.DerivedTxIndex, 10)),
// unique, monotonic eth tx index for this derived tx — drawn from the same
// block-level counter as standard MsgEthereumTx (advanced below).
sdk.NewAttribute(types.AttributeKeyTxIndex, strconv.FormatUint(uint64(txConfig.TxIndex), 10)),
// add event for eth tx gas used, we can't get it from cosmos tx result when it contains multiple eth tx msgs.
sdk.NewAttribute(types.AttributeKeyTxGasUsed, strconv.FormatUint(gasUsed, 10)),
}...)
Expand Down Expand Up @@ -325,6 +326,10 @@ func (k Keeper) DerivedEVMCallWithData(
k.SetLogSizeTransient(ctx, (k.GetLogSizeTransient(ctx))+uint64(len(logs)))
}
}

// Advance the block-level eth tx index so the next eth tx (derived or a
// standard MsgEthereumTx) gets a fresh, unique index. Mirrors ApplyTransaction.
k.SetTxIndexTransient(ctx, uint64(txConfig.TxIndex)+1)
}

if res.Failed() {
Expand Down
41 changes: 41 additions & 0 deletions x/vm/keeper/call_evm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
import (
"fmt"
"math/big"
"strconv"

"github.com/ethereum/go-ethereum/common"

sdk "github.com/cosmos/cosmos-sdk/types"

Check failure on line 10 in x/vm/keeper/call_evm_test.go

View workflow job for this annotation

GitHub Actions / Run golangci-lint

File is not properly formatted (gci)
"github.com/cosmos/evm/contracts"
testconstants "github.com/cosmos/evm/testutil/constants"
utiltx "github.com/cosmos/evm/testutil/tx"
Expand Down Expand Up @@ -337,3 +338,43 @@
})
}
}

// TestDerivedEVMCallAssignsUniqueTxIndex is a regression test for F-2026-17745:
// each derived tx in a block must get a unique, monotonically increasing eth tx
// index (not the legacy constant 9999 shared by all derived txs).
func (suite *KeeperTestSuite) TestDerivedEVMCallAssignsUniqueTxIndex() {
suite.SetupTest()

owner := suite.keyring.GetAddr(0)
recipient := utiltx.GenerateAddress()

contractAddr := suite.DeployTestContract(suite.T(), suite.network.GetContext(), owner, big.NewInt(1_000_000))
ctx := suite.network.GetContext().WithEventManager(sdk.NewEventManager())

const n = 3
for i := 0; i < n; i++ {
suite.Require().NoError(suite.derivedTransfer(ctx, owner, contractAddr, recipient))
}

// Collect the txIndex attribute emitted on each ethereum_tx event.
var indices []uint64
for _, e := range ctx.EventManager().Events() {
if e.Type != evmtypes.EventTypeEthereumTx {
continue
}
for _, a := range e.Attributes {
if a.Key == evmtypes.AttributeKeyTxIndex {
v, err := strconv.ParseUint(a.Value, 10, 64)
suite.Require().NoError(err)
indices = append(indices, v)
}
}
}

suite.Require().Len(indices, n, "one txIndex per derived tx")
suite.Require().NotEqual(uint64(9999), indices[0], "must not use the legacy constant DerivedTxIndex")
for i := 1; i < len(indices); i++ {
suite.Require().Equal(indices[0]+uint64(i), indices[i],

Check failure on line 377 in x/vm/keeper/call_evm_test.go

View workflow job for this annotation

GitHub Actions / Run golangci-lint

G115: integer overflow conversion int -> uint64 (gosec)
"derived txs must get unique, monotonically increasing indices")
}
}
3 changes: 1 addition & 2 deletions x/vm/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,5 @@ const (
)

const (
DerivedTxIndex = 9999
DerivedTxType = 99
DerivedTxType = 99
)
Loading