Skip to content

[F-2026-17745] Derived transactions share a constant txIndex value#18

Merged
0xNilesh merged 5 commits into
audit-fixesfrom
audit/constant-tx-index-derived-tx-issue
Jun 11, 2026
Merged

[F-2026-17745] Derived transactions share a constant txIndex value#18
0xNilesh merged 5 commits into
audit-fixesfrom
audit/constant-tx-index-derived-tx-issue

Conversation

@AryaLanjewar3005

Copy link
Copy Markdown
Collaborator

Description

[F-2026-17745] Derived transactions share a constant txIndex value

Issue

Every derived EVM execution in DerivedEVMCallWithData emitted a hardcoded compile-time constant DerivedTxIndex = 9999 as its transaction index attribute, regardless of its actual position in the block's EVM message sequence.

File: x/vm/keeper/call_evm.go

// Before fix
sdk.NewAttribute(types.AttributeKeyTxIndex, strconv.FormatUint(types.DerivedTxIndex, 10)),
// DerivedTxIndex = 9999, always, for every derived tx in every block

File: x/vm/types/events.go

const (
    DerivedTxIndex = 9999
    DerivedTxType  = 99
)

How standard Eth txs handle indexing

The keeper maintains a transient (per-block, in-memory) counter TxIndexTransient. For each standard MsgEthereumTx:

  1. msg_server.go reads the current counter via GetTxIndexTransient
  2. The tx executes
  3. state_transition.go increments the counter via SetTxIndexTransient
  4. The event carries the real sequential index: 0, 1, 2, 3...

Derived txs never read or incremented this counter. They emitted 9999 and left the counter untouched.

Impact

In a block containing multiple derived transactions or a mix of standard and derived messages:

Execution order Tx type Index emitted (before fix)
1st Standard Eth Tx 0
2nd Standard Eth Tx 1
3rd Derived Tx 9999
4th Derived Tx 9999
5th Standard Eth Tx 2

Three consequences:

  1. eth_getTransactionByBlockNumberAndIndex fails — multiple derived txs share the same index; the endpoint cannot distinguish or resolve them individually.
  2. Transient counter goes out of sync — derived txs don't advance the counter, creating gaps in the index sequence that don't reflect actual execution order.
  3. Explorer and indexer ordering breaks — any system keyed on AttributeKeyTxIndex (block explorers, the KV indexer, tracing tools) sees duplicate 9999 values and cannot order, deduplicate, or resolve derived txs correctly.

Solution

Wire derived transactions into the same TxIndexTransient counter that standard Eth txs use.

In DerivedEVMCallWithData, within the if commit block:

  1. txConfig is already constructed via k.TxConfig(ctx, tx.Hash()) which reads GetTxIndexTransient for its TxIndex field — so txConfig.TxIndex already holds the correct sequential value.
  2. Emit txConfig.TxIndex instead of the hardcoded types.DerivedTxIndex.
  3. After event emission, call SetTxIndexTransient(ctx, txConfig.TxIndex+1) to advance the counter.
// After fix
sdk.NewAttribute(types.AttributeKeyTxIndex, strconv.FormatUint(uint64(txConfig.TxIndex), 10)),

// after event emission, advance the counter
k.SetTxIndexTransient(ctx, uint64(txConfig.TxIndex)+1)

The counter increment is placed inside if commit but outside if !res.Failed() — failed derived txs still consume an index slot, matching Ethereum's behavior where even reverted transactions occupy a position in the block.

Behavior after fix

Execution order Tx type Index emitted (after fix)
1st Standard Eth Tx 0
2nd Standard Eth Tx 1
3rd Derived Tx 2
4th Derived Tx 3
5th Standard Eth Tx 4

Sequential, unique, globally ordered — reflecting actual execution order within the block. DerivedTxType = 99 is retained as a marker to identify derived txs even when they carry a real sequential index.


Author Checklist

All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.

I have...

  • tackled an existing issue or discussed with a team member
  • left instructions on how to review the changes
  • targeted the main branch

@github-actions github-actions Bot added the tests label Jun 11, 2026
@0xNilesh 0xNilesh merged commit a6e46df into audit-fixes Jun 11, 2026
15 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants