diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b365ac9c9b..65e8bbaa7f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ ### Bug fixes - Fix Docker image name clash between Besu and evmtool [#6194](https://github.com/hyperledger/besu/pull/6194) +- Fix `logIndex` in `eth_getTransactionReceipt` JSON RPC method [#6206](https://github.com/hyperledger/besu/pull/6206) ## 23.10.2 diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptResult.java index b2f39d7a287..363d7e50615 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionReceiptResult.java @@ -92,7 +92,8 @@ protected TransactionReceiptResult(final TransactionReceiptWithMetadata receiptW receiptWithMetadata.getBlockNumber(), txn.getHash(), receiptWithMetadata.getBlockHash(), - receiptWithMetadata.getTransactionIndex()); + receiptWithMetadata.getTransactionIndex(), + receiptWithMetadata.getLogIndexOffset()); this.logsBloom = receipt.getBloomFilter().toString(); this.to = txn.getTo().map(Bytes::toHexString).orElse(null); this.transactionHash = txn.getHash().toString(); @@ -192,14 +193,15 @@ private List logReceipts( final long blockNumber, final Hash transactionHash, final Hash blockHash, - final int transactionIndex) { + final int transactionIndex, + final int logIndexOffset) { final List logResults = new ArrayList<>(logs.size()); for (int i = 0; i < logs.size(); i++) { final Log log = logs.get(i); logResults.add( new TransactionReceiptLogResult( - log, blockNumber, transactionHash, blockHash, transactionIndex, i)); + log, blockNumber, transactionHash, blockHash, transactionIndex, i + logIndexOffset)); } return logResults; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java index eede84fb82b..d5228de45e0 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java @@ -183,8 +183,7 @@ public Optional safeBlockHeader() { */ public Optional storageAt( final Address address, final UInt256 storageIndex, final long blockNumber) { - final Hash blockHash = - getBlockHeaderByNumber(blockNumber).map(BlockHeader::getHash).orElse(Hash.EMPTY); + final Hash blockHash = getBlockHashByNumber(blockNumber).orElse(Hash.EMPTY); return storageAt(address, storageIndex, blockHash); } @@ -211,8 +210,7 @@ public Optional storageAt( * @return The balance of the account in Wei. */ public Optional accountBalance(final Address address, final long blockNumber) { - final Hash blockHash = - getBlockHeaderByNumber(blockNumber).map(BlockHeader::getHash).orElse(Hash.EMPTY); + final Hash blockHash = getBlockHashByNumber(blockNumber).orElse(Hash.EMPTY); return accountBalance(address, blockHash); } @@ -236,8 +234,7 @@ public Optional accountBalance(final Address address, final Hash blockHash) * @return The code associated with this address. */ public Optional getCode(final Address address, final long blockNumber) { - final Hash blockHash = - getBlockHeaderByNumber(blockNumber).map(BlockHeader::getHash).orElse(Hash.EMPTY); + final Hash blockHash = getBlockHashByNumber(blockNumber).orElse(Hash.EMPTY); return getCode(address, blockHash); } @@ -263,13 +260,7 @@ public Optional getTransactionCount(final long blockNumber) { if (outsideBlockchainRange(blockNumber)) { return Optional.empty(); } - return Optional.of( - blockchain - .getBlockHashByNumber(blockNumber) - .flatMap(this::blockByHashWithTxHashes) - .map(BlockWithMetadata::getTransactions) - .map(List::size) - .orElse(-1)); + return blockchain.getBlockHashByNumber(blockNumber).map(this::getTransactionCount); } /** @@ -624,22 +615,25 @@ public Optional transactionReceiptByTransactionH // getTransactionLocation should not return if the TX or block doesn't exist, so throwing // on a missing optional is appropriate. final TransactionLocation location = maybeLocation.get(); - final Block block = blockchain.getBlockByHash(location.getBlockHash()).orElseThrow(); - final Transaction transaction = - block.getBody().getTransactions().get(location.getTransactionIndex()); - final Hash blockhash = location.getBlockHash(); + final int transactionIndex = location.getTransactionIndex(); + + final Block block = blockchain.getBlockByHash(blockhash).orElseThrow(); + final Transaction transaction = block.getBody().getTransactions().get(transactionIndex); + final BlockHeader header = block.getHeader(); final List transactionReceipts = blockchain.getTxReceipts(blockhash).orElseThrow(); - final TransactionReceipt transactionReceipt = - transactionReceipts.get(location.getTransactionIndex()); + final TransactionReceipt transactionReceipt = transactionReceipts.get(transactionIndex); long gasUsed = transactionReceipt.getCumulativeGasUsed(); - if (location.getTransactionIndex() > 0) { - gasUsed = - gasUsed - - transactionReceipts.get(location.getTransactionIndex() - 1).getCumulativeGasUsed(); + int logIndexOffset = 0; + if (transactionIndex > 0) { + gasUsed -= transactionReceipts.get(transactionIndex - 1).getCumulativeGasUsed(); + logIndexOffset = + IntStream.range(0, transactionIndex) + .map(i -> transactionReceipts.get(i).getLogsList().size()) + .sum(); } Optional maybeBlobGasUsed = @@ -653,13 +647,14 @@ public Optional transactionReceiptByTransactionH transactionReceipt, transaction, transactionHash, - location.getTransactionIndex(), + transactionIndex, gasUsed, header.getBaseFee(), blockhash, header.getNumber(), maybeBlobGasUsed, - maybeBlobGasPrice)); + maybeBlobGasPrice, + logIndexOffset)); } /** @@ -1075,7 +1070,7 @@ private int logIndexOffset( break; } - logIndexOffset += receipts.get(i).getLogs().size(); + logIndexOffset += receipts.get(i).getLogsList().size(); } return logIndexOffset; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/TransactionReceiptWithMetadata.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/TransactionReceiptWithMetadata.java index 55b85d2678c..5f42ec4d4dd 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/TransactionReceiptWithMetadata.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/TransactionReceiptWithMetadata.java @@ -32,6 +32,7 @@ public class TransactionReceiptWithMetadata { private final Transaction transaction; private final Optional blobGasUsed; private final Optional blobGasPrice; + private final int logIndexOffset; private TransactionReceiptWithMetadata( final TransactionReceipt receipt, @@ -43,7 +44,8 @@ private TransactionReceiptWithMetadata( final Hash blockHash, final long blockNumber, final Optional blobGasUsed, - final Optional blobGasPrice) { + final Optional blobGasPrice, + final int logIndexOffset) { this.receipt = receipt; this.transactionHash = transactionHash; this.transactionIndex = transactionIndex; @@ -54,6 +56,7 @@ private TransactionReceiptWithMetadata( this.transaction = transaction; this.blobGasUsed = blobGasUsed; this.blobGasPrice = blobGasPrice; + this.logIndexOffset = logIndexOffset; } public static TransactionReceiptWithMetadata create( @@ -66,7 +69,8 @@ public static TransactionReceiptWithMetadata create( final Hash blockHash, final long blockNumber, final Optional blobGasUsed, - final Optional blobGasPrice) { + final Optional blobGasPrice, + final int logIndexOffset) { return new TransactionReceiptWithMetadata( receipt, transaction, @@ -77,7 +81,8 @@ public static TransactionReceiptWithMetadata create( blockHash, blockNumber, blobGasUsed, - blobGasPrice); + blobGasPrice, + logIndexOffset); } public TransactionReceipt getReceipt() { @@ -121,4 +126,8 @@ public Optional getBlobGasUsed() { public Optional getBlobGasPrice() { return blobGasPrice; } + + public int getLogIndexOffset() { + return logIndexOffset; + } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/TransactionDataFetcherTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/TransactionDataFetcherTest.java index c4aee54176b..aa780d42ccd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/TransactionDataFetcherTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/TransactionDataFetcherTest.java @@ -75,7 +75,8 @@ void emptyBlobs() throws Exception { fakedHash, 1, Optional.empty(), - Optional.empty()); + Optional.empty(), + 0); when(query.transactionReceiptByTransactionHash(any(), any())) .thenReturn(Optional.of(transactionReceiptWithMetadata)); @@ -109,7 +110,8 @@ void hasZeroBlobs() throws Exception { fakedHash, 1, Optional.of(0L), - Optional.of(Wei.ZERO)); + Optional.of(Wei.ZERO), + 0); when(query.transactionReceiptByTransactionHash(any(), any())) .thenReturn(Optional.of(transactionReceiptWithMetadata)); @@ -143,7 +145,8 @@ void hasOneBlob() throws Exception { fakedHash, 1, Optional.of(blobGasUsed), - Optional.of(blobGasPrice)); + Optional.of(blobGasPrice), + 0); when(query.transactionReceiptByTransactionHash(any(), any())) .thenReturn(Optional.of(transactionReceiptWithMetadata)); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java index 6c094c12deb..a773048d965 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java @@ -103,7 +103,8 @@ public class EthGetTransactionReceiptTest { blockHash, 4, Optional.empty(), - Optional.empty()); + Optional.empty(), + 0); private final TransactionReceiptWithMetadata rootReceiptWithMetaData = TransactionReceiptWithMetadata.create( rootReceipt, @@ -115,7 +116,8 @@ public class EthGetTransactionReceiptTest { blockHash, 4, Optional.empty(), - Optional.empty()); + Optional.empty(), + 0); private final ProtocolSpec rootTransactionTypeSpec = new ProtocolSpec( @@ -243,7 +245,8 @@ public void shouldWorkFor1559Txs() { blockHash, 4, Optional.empty(), - Optional.empty()); + Optional.empty(), + 0); when(blockchainQueries.transactionReceiptByTransactionHash(receiptHash, protocolSchedule)) .thenReturn(Optional.of(transactionReceiptWithMetadata)); when(protocolSchedule.getByBlockHeader(blockHeader(1))).thenReturn(rootTransactionTypeSpec);