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
}
]
}
@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
eth_getTransactioneth_getBlocketh_getTransactionReciept on each, counting the number of logslogIndex as position within transaction
eth_getTransactionReceiptIn 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:
transactionIndex and blockNumberPerhaps 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