Go-ethereum: get_TransactionReceipt logIndex and transactionIndex is not correct

Created on 1 Dec 2015  路  17Comments  路  Source: ethereum/go-ethereum

Working on a private chain, I noticed that logIndex seems to follow be the order of a transaction and transactionIndex not set to what it should be. For example, note the below block with 2 transactions, each containing 1 log. The "position" of these logs in the chain should be 7494.0.0 and 7494.1.0 where the format is BlockIndex.TransactionIndex.LogIndex, each as a subset of the other. Instead, go-ethereum reports the position as 7494.0.1 and 7494.0/1.1. The second receipt actually has conflicting information, with the transactionIndex being reported at "1" on the transaction itself but "0" on the composed log.

The positional values should be defined as follows:
BlockHeight (in main chain)
Transaction index (within the block)
Log index (within the transaction)

{
  "number": 7494,
  "hash": "0xf40e42e96dd65293fec0c964949c7fb0714950ad68f5dbc149976373863cb706",
  "parentHash": "0x64aade970cb55d33dac4de99fdfe586b33c273bd01aa9d2c5130891398ee7337",
  "nonce": "0x62ebcb509371bfa9",
  "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  "logsBloom": "0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000400000000000000000000000000000000000040000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000440000000000000000",
  "transactionsRoot": "0xabbadcac389e791d49707038e786e16b1f95133b476fbf89c170e675a58b19c3",
  "stateRoot": "0x1edf9403b6d46043e88c1df1135c27fc689503d18b2cdd1804a04197d4645c24",
  "receiptRoot": "0x0fd029c2da92e37cbb396d1fee0287c9804d8cc72cbb7c8cad81ebbbb68b1e29",
  "miner": "0x392af429f1b9537f28d97b8467e4b4e3498d5108",
  "difficulty": "2260665",
  "totalDifficulty": "6628082686",
  "size": 788,
  "extraData": "0xd883010301844765746887676f312e352e318664617277696e",
  "gasLimit": 3141592,
  "gasUsed": 97110,
  "timestamp": 1448536345,
  "transactions": [
    "0x350fb0718093692501fc33dec42b5a4e55860747b4224a3ee0625d1336923854",
    "0xdce4c53b4572f4f87a6a65ae149bbdf283f7517242696e5af7bfa48d4d9ea343"
  ],
  "uncles": []
}

Receipt 350fb0:

{
  "transactionHash": "0x350fb0718093692501fc33dec42b5a4e55860747b4224a3ee0625d1336923854",
  "transactionIndex": 0,
  "blockNumber": 7494,
  "blockHash": "0xf40e42e96dd65293fec0c964949c7fb0714950ad68f5dbc149976373863cb706",
  "cumulativeGasUsed": 22444,
  "gasUsed": 22444,
  "contractAddress": null,
  "logs": [
    {
      "address": "0x63f33b08404987648ce2dde79715e14e8b69e4d8",
      "topics": [
        "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"
      ],
      "data": "0x000000000000000000000000392af429f1b9537f28d97b8467e4b4e3498d51080000000000000000000000000000000000000000000000000000000000000001",
      "blockNumber": 7494,
      "logIndex": 0,
      "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
      "transactionHash": "0x350fb0718093692501fc33dec42b5a4e55860747b4224a3ee0625d1336923854",
      "transactionIndex": 0
    }
  ]
}

Receipt dce4c5:

{
  "transactionHash": "0xdce4c53b4572f4f87a6a65ae149bbdf283f7517242696e5af7bfa48d4d9ea343",
  "transactionIndex": 1,
  "blockNumber": 7494,
  "blockHash": "0xf40e42e96dd65293fec0c964949c7fb0714950ad68f5dbc149976373863cb706",
  "cumulativeGasUsed": 97110,
  "gasUsed": 74666,
  "contractAddress": null,
  "logs": [
    {
      "address": "0x63f33b08404987648ce2dde79715e14e8b69e4d8",
      "topics": [
        "0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda"
      ],
      "data": "0x000000000000000000000000392af429f1b9537f28d97b8467e4b4e3498d51081e170c489308caf0fe6d059b7da016bf187ec33420b8144a4db938a6e0a22c8d",
      "blockNumber": 7494,
      "logIndex": 1,
      "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
      "transactionHash": "0xdce4c53b4572f4f87a6a65ae149bbdf283f7517242696e5af7bfa48d4d9ea343",
      "transactionIndex": 0
    }
  ]
}
on-hold

All 17 comments

@tgerring, according to the official json docs the logIndex is the index of the log in the block and not in the transaction.

Could you try PR #2030?

The problem is that this definition is impractical. If the logIndex is based on the log position in the block, then it is impossible to identify a specific log without fetching all transactions in a block and looping to count the number of logs preceding the particular log. In fact, this is the point of having a transactionIndex. The logIndex should instead be the index of within the particular transaction.

Given a txhash and logIndex, here's the difference:
logIndex as position within block

  1. Given txhash, fetch transaction with eth_getTransaction
  2. From transaction, use blockHash to fetch Block with eth_getBlock
  3. From block, loop through transactions, calling eth_getTransactionReciept on each, counting the number of logs
    4 .When the total log count == logIndex, you have located the correct log

logIndex as position within transaction

  1. Given txhash, fetch transaction receipt with eth_getTransactionReceipt
  2. The log is located at logs[logIndex]

In summary, when logIndex tracks the position of the log within the block, it actually combines the txIndex and logIndex into a single confusing parameter. Instead, the bias of txIndex should be removed, so logIndex doesn't need to know anything about its containing block, only the transaction

Pinging @frozeman for his input

I agree with @tgerring here, it doesn't make real sense to make it block specific, as this makes the log index rather useless.
The only benefit it gives is to give an indication in which order they were processed. (Which can also be found out by checking the tx index too)

Im not sure how this is implemented in cpp @debris

I've been looking into this carefully between geth and parity. Geth and parity both report transactionIndexes starting from '0' within a block. Parity (at least its latest version) reports logIndexes per transaction starting with '0'. Geth (prior to 1.5.x) reports logIndexes per block starting with '1'

So there's more than one different inconsistencies. The docs say that each item is an 'integer of the [item]'s index position in the block. null when its pending'.

I agree with tgerring, that the transactionIndex should be per block (because transactions are data members of blocks), and the logIndex should be per transaction (because logs are conceptually part of a transaction). Both should index starting with '0' not '1', but in either case, both should index starting with the same number.

Fixing this will be a breaking change for existing apps using either transactionIndex or logIndex (whichever gets changed), and the docs will have to be fixed.

I think it's also important to track that this gets made consistent between Parity and geth so as to make switching RPC providers painless.

Fixing this would be a breaking change. However, this would make logIndex:

  • consistent with transactionIndex and blockNumber
  • useful
  • far less compute and bandwidth to fetch a specific class of events

Perhaps it could be done for the next major version?

+1 I think, that logIndex should be transaction specific. It is really useful in many cases.

I just ran into this because it seemed strange geth indexed the logs as a position within the block, but I had to call client.ImportReceipt on each Txn to actually count how many logs are within the block total. Also confusing was this code comment stating logIndex is based on the position in the Receipt, but is actually based on the position in the Block currently.

(Incidentally what I was trying to do with create a buffered channel of len(logs) because as geth currently stands max(log_index) would be the appropriate channel size, but there's no way to find out what max is without iterating each receipt.)

@bas-vk are you still working on this? I'm going to remove the in-progress label.

We can do a similar fix to Parity. Then the API doesn't break, but the functionality gets shipped https://github.com/paritytech/parity-ethereum/pull/3995

Feature request added: #18407

OMG can somebody take care of this finally?

Feel free to take care of it.

But I am not premine beneficiary...

Then find someone who is I guess.

Ok, so we don't get what the issue here is.

The receipt returned an array of logs. If you access logs[5], then that's... "index 5 within the transaction". I don't see why we'd need a special field to spill this out.

@karalabe right, but I think that's incorrect because logs need to be indexed to the _block_ not indexed to the _transaction_?

return values from eth_getFilterChanges:
logIndex: QUANTITY - integer of the log index position in the block. null when its pending log.

So if txn[0] has 2 logs, and txn[1] has 3 logs the proper logIndex values should be:

txn[0].logs[0] = 0
txn[0].logs[1] = 1
txn[1].logs[0] = 2
txn[1].logs[1] = 3
txn[1].logs[2] = 4

but instead geth returns:

txn[0].logs[0] = 0
txn[0].logs[1] = 1
txn[1].logs[0] = 0
txn[1].logs[1] = 1
txn[1].logs[2] = 2

Was this page helpful?
0 / 5 - 0 ratings