From 41b35a98bef387e7f55163e5502d974fe1e84d34 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Tue, 13 Jun 2023 13:48:58 +1000 Subject: [PATCH] Add dataGasUsed and dataGasPrice to receipts for 4844 txs (#5554) Signed-off-by: Gabriel-Trintinalia --- .../pojoadapter/TransactionAdapter.java | 12 +- .../methods/EthGetMinerDataByBlockHash.java | 3 +- .../methods/EthGetTransactionReceipt.java | 9 +- .../results/TransactionReceiptResult.java | 21 ++- .../jsonrpc/methods/EthJsonRpcMethods.java | 2 +- .../ethereum/api/query/BlockchainQueries.java | 53 +++++++- .../query/TransactionReceiptWithMetadata.java | 24 +++- .../methods/EthGetTransactionReceiptTest.java | 121 ++++++++++++++++-- .../retesteth/methods/TestGetLogHash.java | 4 +- 9 files changed, 225 insertions(+), 24 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java index 49c1da5da65..db849fdeb5e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java @@ -17,12 +17,14 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.api.graphql.GraphQLContextType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import java.util.ArrayList; @@ -46,12 +48,15 @@ private Optional getReceipt( final DataFetchingEnvironment environment) { if (transactionReceiptWithMetadata == null) { final BlockchainQueries query = getBlockchainQueries(environment); + final ProtocolSchedule protocolSchedule = + environment.getGraphQlContext().get(GraphQLContextType.PROTOCOL_SCHEDULE); + final Transaction transaction = transactionWithMetadata.getTransaction(); if (transaction == null) { transactionReceiptWithMetadata = Optional.empty(); } else { transactionReceiptWithMetadata = - query.transactionReceiptByTransactionHash(transaction.getHash()); + query.transactionReceiptByTransactionHash(transaction.getHash(), protocolSchedule); } } return transactionReceiptWithMetadata; @@ -187,6 +192,9 @@ public Optional getCreatedContract(final DataFetchingEnvironment public List getLogs(final DataFetchingEnvironment environment) { final BlockchainQueries query = getBlockchainQueries(environment); + final ProtocolSchedule protocolSchedule = + environment.getGraphQlContext().get(GraphQLContextType.PROTOCOL_SCHEDULE); + final Hash hash = transactionWithMetadata.getTransaction().getHash(); final Optional maybeBlockHeader = @@ -201,7 +209,7 @@ public List getLogs(final DataFetchingEnvironment environment) { } final Optional maybeTransactionReceiptWithMetadata = - query.transactionReceiptByTransactionHash(hash); + query.transactionReceiptByTransactionHash(hash, protocolSchedule); final List results = new ArrayList<>(); if (maybeTransactionReceiptWithMetadata.isPresent()) { final List logs = diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockHash.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockHash.java index 424f0f772ee..1d3d647e3f2 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockHash.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetMinerDataByBlockHash.java @@ -86,7 +86,8 @@ public static MinerDataResult createMinerDataResult( .map( t -> blockchainQueries - .transactionReceiptByTransactionHash(t.getTransaction().getHash()) + .transactionReceiptByTransactionHash( + t.getTransaction().getHash(), protocolSchedule) .map( receipt -> receipt diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceipt.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceipt.java index d85abb1a96a..78c5f3b6504 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceipt.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceipt.java @@ -24,14 +24,19 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionReceiptStatusResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.TransactionReceiptType; public class EthGetTransactionReceipt implements JsonRpcMethod { private final BlockchainQueries blockchainQueries; - public EthGetTransactionReceipt(final BlockchainQueries blockchainQueries) { + private final ProtocolSchedule protocolSchedule; + + public EthGetTransactionReceipt( + final BlockchainQueries blockchainQueries, final ProtocolSchedule protocolSchedule) { this.blockchainQueries = blockchainQueries; + this.protocolSchedule = protocolSchedule; } @Override @@ -44,7 +49,7 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final Hash hash = requestContext.getRequiredParameter(0, Hash.class); final TransactionReceiptResult result = blockchainQueries - .transactionReceiptByTransactionHash(hash) + .transactionReceiptByTransactionHash(hash, protocolSchedule) .map(this::getResult) .orElse(null); return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), result); 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 db032289bde..7b481561736 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 @@ -46,7 +46,9 @@ "transactionHash", "transactionIndex", "revertReason", - "type" + "type", + "dataGasUsed", + "dataGasPrice" }) public abstract class TransactionReceiptResult { @@ -67,6 +69,9 @@ public abstract class TransactionReceiptResult { protected final TransactionReceipt receipt; protected final String type; + private final String dataGasUsed; + private final String dataGasPrice; + protected TransactionReceiptResult(final TransactionReceiptWithMetadata receiptWithMetadata) { final Transaction txn = receiptWithMetadata.getTransaction(); this.receipt = receiptWithMetadata.getReceipt(); @@ -76,6 +81,8 @@ protected TransactionReceiptResult(final TransactionReceiptWithMetadata receiptW this.cumulativeGasUsed = Quantity.create(receipt.getCumulativeGasUsed()); this.from = txn.getSender().toString(); this.gasUsed = Quantity.create(receiptWithMetadata.getGasUsed()); + this.dataGasUsed = receiptWithMetadata.getDataGasUsed().map(Quantity::create).orElse(null); + this.dataGasPrice = receiptWithMetadata.getDataGasPrice().map(Quantity::create).orElse(null); this.effectiveGasPrice = Quantity.create(txn.getEffectiveGasPrice(receiptWithMetadata.getBaseFee())); @@ -127,6 +134,18 @@ public String getGasUsed() { return gasUsed; } + @JsonGetter(value = "dataGasUsed") + @JsonInclude(JsonInclude.Include.NON_NULL) + public String getDataGasUsed() { + return dataGasUsed; + } + + @JsonGetter(value = "dataGasPrice") + @JsonInclude(JsonInclude.Include.NON_NULL) + public String getDataGasPrice() { + return dataGasPrice; + } + @JsonGetter(value = "effectiveGasPrice") public String getEffectiveGasPrice() { return effectiveGasPrice; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java index 43edba38359..2119cfda149 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java @@ -142,7 +142,7 @@ protected Map create() { new EthGetTransactionByBlockHashAndIndex(blockchainQueries), new EthGetTransactionByBlockNumberAndIndex(blockchainQueries), new EthGetTransactionCount(blockchainQueries, transactionPool.getPendingTransactions()), - new EthGetTransactionReceipt(blockchainQueries), + new EthGetTransactionReceipt(blockchainQueries, protocolSchedule), new EthUninstallFilter(filterManager), new EthGetFilterChanges(filterManager), new EthGetFilterLogs(filterManager), 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 96e01fdb1b2..de6c67017de 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 @@ -18,6 +18,7 @@ import static org.hyperledger.besu.ethereum.api.query.cache.TransactionLogBloomCacher.BLOCKS_PER_BLOOM_CACHE; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.ApiConfiguration; @@ -33,6 +34,8 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.log.LogsBloomFilter; @@ -612,7 +615,7 @@ public Optional transactionLocationByHash(final Hash transa * @return The transaction receipt associated with the referenced transaction. */ public Optional transactionReceiptByTransactionHash( - final Hash transactionHash) { + final Hash transactionHash, final ProtocolSchedule protocolSchedule) { final Optional maybeLocation = blockchain.getTransactionLocation(transactionHash); if (maybeLocation.isEmpty()) { @@ -639,6 +642,12 @@ public Optional transactionReceiptByTransactionH - transactionReceipts.get(location.getTransactionIndex() - 1).getCumulativeGasUsed(); } + Optional maybeDataGasUsed = + getDataGasUsed(transaction, protocolSchedule.getByBlockHeader(header)); + + Optional maybeDataGasPrice = + getDataGasPrice(transaction, header, protocolSchedule.getByBlockHeader(header)); + return Optional.of( TransactionReceiptWithMetadata.create( transactionReceipt, @@ -648,7 +657,47 @@ public Optional transactionReceiptByTransactionH gasUsed, header.getBaseFee(), blockhash, - header.getNumber())); + header.getNumber(), + maybeDataGasUsed, + maybeDataGasPrice)); + } + + /** + * Calculates the data gas used for data in a transaction. + * + * @param transaction the transaction to calculate the gas for + * @param protocolSpec the protocol specification to use for gas calculation + * @return an Optional containing the data gas used for data if the transaction type supports + * blobs, otherwise returns an empty Optional + */ + private Optional getDataGasUsed( + final Transaction transaction, final ProtocolSpec protocolSpec) { + return transaction.getType().supportsBlob() + ? Optional.of(protocolSpec.getGasCalculator().dataGasCost(transaction.getBlobCount())) + : Optional.empty(); + } + + /** + * Calculates the data gas price for data in a transaction. + * + * @param transaction the transaction to calculate the gas price for + * @param header the block header of the current block + * @param protocolSpec the protocol specification to use for gas price calculation + * @return an Optional containing the data gas price for data if the transaction type supports + * blobs, otherwise returns an empty Optional + */ + private Optional getDataGasPrice( + final Transaction transaction, final BlockHeader header, final ProtocolSpec protocolSpec) { + if (transaction.getType().supportsBlob()) { + return blockchain + .getBlockHeader(header.getParentHash()) + .map( + parentHeader -> + protocolSpec + .getFeeMarket() + .dataPrice(parentHeader.getExcessDataGas().orElse(DataGas.ZERO))); + } + return Optional.empty(); } /** 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 059c7aedc1f..77a910cfc1b 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 @@ -30,6 +30,8 @@ public class TransactionReceiptWithMetadata { private final long blockNumber; private final Hash blockHash; private final Transaction transaction; + private final Optional dataGasUsed; + private final Optional dataGasPrice; private TransactionReceiptWithMetadata( final TransactionReceipt receipt, @@ -39,7 +41,9 @@ private TransactionReceiptWithMetadata( final long gasUsed, final Optional baseFee, final Hash blockHash, - final long blockNumber) { + final long blockNumber, + final Optional dataGasUsed, + final Optional dataGasPrice) { this.receipt = receipt; this.transactionHash = transactionHash; this.transactionIndex = transactionIndex; @@ -48,6 +52,8 @@ private TransactionReceiptWithMetadata( this.blockHash = blockHash; this.blockNumber = blockNumber; this.transaction = transaction; + this.dataGasUsed = dataGasUsed; + this.dataGasPrice = dataGasPrice; } public static TransactionReceiptWithMetadata create( @@ -58,7 +64,9 @@ public static TransactionReceiptWithMetadata create( final long gasUsed, final Optional baseFee, final Hash blockHash, - final long blockNumber) { + final long blockNumber, + final Optional dataGasUsed, + final Optional dataGasPrice) { return new TransactionReceiptWithMetadata( receipt, transaction, @@ -67,7 +75,9 @@ public static TransactionReceiptWithMetadata create( gasUsed, baseFee, blockHash, - blockNumber); + blockNumber, + dataGasUsed, + dataGasPrice); } public TransactionReceipt getReceipt() { @@ -103,4 +113,12 @@ public long getGasUsed() { public Optional getBaseFee() { return baseFee; } + + public Optional getDataGasUsed() { + return dataGasUsed; + } + + public Optional getDataGasPrice() { + return dataGasPrice; + } } 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 def0693a75b..bd0baddfcf9 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 @@ -15,12 +15,15 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.GasLimitCalculator; @@ -31,6 +34,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionReceiptStatusResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; +import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.chain.TransactionLocation; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; @@ -39,14 +46,19 @@ import org.hyperledger.besu.ethereum.mainnet.PoWHasher; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.feemarket.CancunFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; +import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.util.Collections; +import java.util.List; import java.util.Optional; import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256s; import org.junit.Test; @@ -82,10 +94,28 @@ public class EthGetTransactionReceiptTest { private final TransactionReceiptWithMetadata statusReceiptWithMetadata = TransactionReceiptWithMetadata.create( - statusReceipt, transaction, hash, 1, 2, Optional.empty(), blockHash, 4); + statusReceipt, + transaction, + hash, + 1, + 2, + Optional.empty(), + blockHash, + 4, + Optional.empty(), + Optional.empty()); private final TransactionReceiptWithMetadata rootReceiptWithMetaData = TransactionReceiptWithMetadata.create( - rootReceipt, transaction, hash, 1, 2, Optional.empty(), blockHash, 4); + rootReceipt, + transaction, + hash, + 1, + 2, + Optional.empty(), + blockHash, + 4, + Optional.empty(), + Optional.empty()); private final ProtocolSpec rootTransactionTypeSpec = new ProtocolSpec( @@ -149,9 +179,12 @@ public class EthGetTransactionReceiptTest { @SuppressWarnings("unchecked") private final ProtocolSchedule protocolSchedule = mock(ProtocolSchedule.class); - private final BlockchainQueries blockchain = mock(BlockchainQueries.class); + private final Blockchain blockchain = mock(Blockchain.class); + + private final BlockchainQueries blockchainQueries = + spy(new BlockchainQueries(blockchain, mock(WorldStateArchive.class))); private final EthGetTransactionReceipt ethGetTransactionReceipt = - new EthGetTransactionReceipt(blockchain); + new EthGetTransactionReceipt(blockchainQueries, protocolSchedule); private final String receiptString = "0xcbef69eaf44af151aa66677ae4b8d8c343a09f667c873a3a6f4558fa4051fa5f"; private final Hash receiptHash = @@ -162,8 +195,8 @@ public class EthGetTransactionReceiptTest { @Test public void shouldCreateAStatusTransactionReceiptWhenStatusTypeProtocol() { - when(blockchain.headBlockNumber()).thenReturn(1L); - when(blockchain.transactionReceiptByTransactionHash(receiptHash)) + when(blockchainQueries.headBlockNumber()).thenReturn(1L); + when(blockchainQueries.transactionReceiptByTransactionHash(receiptHash, protocolSchedule)) .thenReturn(Optional.of(statusReceiptWithMetadata)); when(protocolSchedule.getByBlockHeader(blockHeader(1))).thenReturn(statusTransactionTypeSpec); @@ -178,8 +211,8 @@ public void shouldCreateAStatusTransactionReceiptWhenStatusTypeProtocol() { @Test public void shouldCreateARootTransactionReceiptWhenRootTypeProtocol() { - when(blockchain.headBlockNumber()).thenReturn(1L); - when(blockchain.transactionReceiptByTransactionHash(receiptHash)) + when(blockchainQueries.headBlockNumber()).thenReturn(1L); + when(blockchainQueries.transactionReceiptByTransactionHash(receiptHash, protocolSchedule)) .thenReturn(Optional.of(rootReceiptWithMetaData)); when(protocolSchedule.getByBlockHeader(blockHeader(1))).thenReturn(rootTransactionTypeSpec); @@ -193,14 +226,23 @@ public void shouldCreateARootTransactionReceiptWhenRootTypeProtocol() { @Test public void shouldWorkFor1559Txs() { - when(blockchain.headBlockNumber()).thenReturn(1L); + when(blockchainQueries.headBlockNumber()).thenReturn(1L); final Transaction transaction1559 = new BlockDataGenerator().transaction(TransactionType.EIP1559); final Wei baseFee = Wei.ONE; final TransactionReceiptWithMetadata transactionReceiptWithMetadata = TransactionReceiptWithMetadata.create( - statusReceipt, transaction1559, hash, 1, 2, Optional.of(baseFee), blockHash, 4); - when(blockchain.transactionReceiptByTransactionHash(receiptHash)) + statusReceipt, + transaction1559, + hash, + 1, + 2, + Optional.of(baseFee), + blockHash, + 4, + Optional.empty(), + Optional.empty()); + when(blockchainQueries.transactionReceiptByTransactionHash(receiptHash, protocolSchedule)) .thenReturn(Optional.of(transactionReceiptWithMetadata)); when(protocolSchedule.getByBlockHeader(blockHeader(1))).thenReturn(rootTransactionTypeSpec); @@ -218,6 +260,63 @@ public void shouldWorkFor1559Txs() { transaction1559.getMaxFeePerGas().get())); } + /** + * Test case to verify that the TransactionReceiptStatusResult contains data gas used and data gas + * price when the transaction type is TransactionType#BLOB + */ + @Test + public void shouldContainDataGasUsedAndDataGasPriceWhenBlobTransaction() { + + var hash = Hash.wrap(Bytes32.random()); + mockBlockWithBlobTransaction(hash, 1L); + when(blockchain.getTxReceipts(hash)).thenReturn(Optional.of(List.of(statusReceipt))); + // Call the real method to get the transaction receipt by transaction hash + when(blockchainQueries.transactionReceiptByTransactionHash(receiptHash, protocolSchedule)) + .thenCallRealMethod(); + + final JsonRpcSuccessResponse response = + (JsonRpcSuccessResponse) ethGetTransactionReceipt.response(request); + final TransactionReceiptStatusResult result = + (TransactionReceiptStatusResult) response.getResult(); + + assertThat(result.getType()).isEqualTo("0x3"); + assertThat(result.getDataGasUsed()).isEqualTo("0x20000"); + assertThat(result.getDataGasPrice()).isEqualTo("0x1"); + } + + private void mockBlockWithBlobTransaction(final Hash blockHash, final long blockNumber) { + Hash parentHash = Hash.wrap(Bytes32.random()); + TransactionLocation transactionLocation = mock(TransactionLocation.class); + Block block = mock(Block.class); + BlockBody body = mock(BlockBody.class); + BlockHeader header = mock(BlockHeader.class); + BlockHeader parentHeader = mock(BlockHeader.class); + when(transactionLocation.getBlockHash()).thenReturn(blockHash); + when(transactionLocation.getTransactionIndex()).thenReturn(0); + when(header.getNumber()).thenReturn(blockNumber); + when(header.getBlockHash()).thenReturn(blockHash); + when(header.getParentHash()).thenReturn(parentHash); + when(blockchain.getBlockHeader(parentHash)).thenReturn(Optional.of(parentHeader)); + when(block.getHeader()).thenReturn(header); + when(block.getBody()).thenReturn(body); + when(body.getTransactions()) + .thenReturn(List.of(new BlockDataGenerator().transaction(TransactionType.BLOB))); + when(parentHeader.getExcessDataGas()).thenReturn(Optional.of(DataGas.of(1000))); + when(blockchain.getBlockByHash(blockHash)).thenReturn(Optional.of(block)); + mockProtocolSpec(header); + when(blockchain.getTransactionLocation(receiptHash)) + .thenReturn(Optional.of(transactionLocation)); + } + + private void mockProtocolSpec(final BlockHeader blockHeader) { + FeeMarket feeMarket = mock(CancunFeeMarket.class); + when(feeMarket.dataPrice(any())).thenCallRealMethod(); + ProtocolSpec spec = mock(ProtocolSpec.class); + when(spec.getFeeMarket()).thenReturn(feeMarket); + when(spec.getGasCalculator()).thenReturn(new CancunGasCalculator()); + when(protocolSchedule.getByBlockHeader(blockHeader)).thenReturn(spec); + } + private BlockHeader blockHeader(final long number) { return new BlockHeaderTestFixture().number(number).buildHeader(); } diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java index 637110b74a5..a0790c9fcdb 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java @@ -43,7 +43,9 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final Hash txHash = requestContext.getRequiredParameter(0, Hash.class); final Optional receipt = - context.getBlockchainQueries().transactionReceiptByTransactionHash(txHash); + context + .getBlockchainQueries() + .transactionReceiptByTransactionHash(txHash, context.getProtocolSchedule()); return new JsonRpcSuccessResponse( requestContext.getRequest().getId(), receipt.map(this::calculateLogHash).orElse(Hash.EMPTY_LIST_HASH).toString());