Skip to content

fix(fab3): GetTransactionReceipt leaks EVM logs from MVCC-invalidated transactions#64

Closed
Aman-Cool wants to merge 1 commit intohyperledger:mainfrom
Aman-Cool:fix/mvcc-receipt-log-leakage
Closed

fix(fab3): GetTransactionReceipt leaks EVM logs from MVCC-invalidated transactions#64
Aman-Cool wants to merge 1 commit intohyperledger:mainfrom
Aman-Cool:fix/mvcc-receipt-log-leakage

Conversation

@Aman-Cool
Copy link

Bug: GetTransactionReceipt returns logs for MVCC-invalidated transactions

What's wrong

Found this while hammering the gateway with concurrent transactions. Two clients writing to the same contract key → one gets MVCC-conflicted by the committer -> calling eth_getTransactionReceipt on the dead transaction returns "status": "0x0" (correct) with a non-empty logs array (very wrong).

Those logs came from the endorser's simulation, state changes that the committer threw away. Nothing committed, but the receipt says otherwise.

What made it click was checking eth_getLogs for the same block. No logs. So GetTransactionReceipt and GetLogs are looking at the exact same bytes in the same block and returning contradictory answers. GetLogs already had the validity guard:

if !transactionsFilter.IsValid(transactionIndex) {
    continue // correctly skips invalid txs
}

GetTransactionReceipt sets status correctly from the same flag, then completely ignores it when extracting logs. Classic "fixed half the problem" situation.

There's also a secondary issue: failed contract deployments were still getting a contractAddress in the receipt. No contract exists at that address, the deployment was invalidated, but we were advertising it anyway.

Why it's bad

EIP-658 is explicit: status = 0x0 means empty logs. Every Ethereum client library, indexer, and dApp is built around this. An ERC-20 Transfer event in a failed receipt will get processed as a real transfer by anything listening. Under low load you'd never see this, MVCC conflicts only show up under real concurrency, which is exactly when you need your receipts to be correct.

The fix

Gate log extraction and contractAddress on txnValidValue == 1. Two extra if blocks. Valid transactions behave identically to before. Invalid transactions get empty logs and no contract address, matching what GetLogs already returns and what EIP-658 requires.

Tests

Two new specs in ethservice_test.go, one for an MVCC-invalidated call transaction (asserts status=0x0, logs=nil), one for an MVCC-invalidated deployment (asserts contractAddress=""). All 83 existing specs still pass.

…tTransactionReceipt

Signed-off-by: Aman-Cool <aman017102007@gmail.com>
@Aman-Cool Aman-Cool force-pushed the fix/mvcc-receipt-log-leakage branch from c3c1a54 to 548571c Compare March 10, 2026 21:59
@Aman-Cool
Copy link
Author

Hey @mbrandenburger @pasquale95, just wanted to flag a few things to make your review easier.
The diff is huge but please don't let that throw you off, the only thing that actually matters is around line 186-220 in ethservice.go. Everything else in the file is carry-over from the archived fabric-chaincode-evm repo, untouched.
The bug itself is real and reproducible, GetTransactionReceipt was serving EVM logs from MVCC-invalidated transactions. The endorser embeds simulation output in every block transaction regardless of whether the committer accepts it, and we were reading those events and returning them in receipts without checking the validity flag first. So clients were seeing non-empty logs on status: 0x0 receipts, which violates EIP-658 and breaks any event-driven application sitting on top of this.
The weird part is GetLogs was already doing it right, it had the validity check. GetTransactionReceipt just missed it. So the fix is literally bringing one function in line with what the other was already doing.
Two things worth double checking on your end:

The txnValidValue == 1 guard placement, want to make sure it reads cleanly and there's no edge case I missed around the to field handling for failed txs
The two new test cases in ethservice_test.go — they use TxValidationCode_MVCC_READ_CONFLICT directly in the block metadata which mirrors exactly how the committer marks conflicts in production

Happy to answer any questions or make changes if something looks off. Thanks for taking a look!

@mbrandenburger
Copy link
Contributor

@Aman-Cool Thank you for creating this PR! I believe this PR belongs in a different repository (i.e., https://github.com/hyperledger-archives/fabric-chaincode-evm). Closing this for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants