Skip to content

Commit

Permalink
Fix NoSuchElementException in Transaction Receipt Logic (#2477)
Browse files Browse the repository at this point in the history
Signed-off-by: Ratan Rai Sur <[email protected]>
  • Loading branch information
RatanRSur authored Jun 25, 2021
1 parent ddc95c4 commit 375d9b6
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 30 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
### Bug Fixes
- Ibft2 could create invalid RoundChange messages in some circumstances containing duplicate prepares [\#2449](https://github.com/hyperledger/besu/pull/2449)
- Updated `eth_sendRawTransaction` to return an error when maxPriorityFeePerGas exceeds maxFeePerGas [\#2424](https://github.com/hyperledger/besu/pull/2424)
- Fixed NoSuchElementException with EIP1559 transaction receipts when using eth_getTransactionReceipt [\#2477](https://github.com/hyperledger/besu/pull/2477)

### Early Access Features
This release contains the activation blocks for London across all supported testnets. They are:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public static MinerDataResult createMinerDataResult(
receipt ->
receipt
.getTransaction()
.calcEffectiveGas(receipt.getBaseFee())
.getEffectiveGasPrice(receipt.getBaseFee())
.multiply(receipt.getGasUsed()))
.orElse(Wei.ZERO))
.reduce(Wei.ZERO, BaseUInt256Value::add);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@

public class EthGetTransactionReceipt implements JsonRpcMethod {

private final BlockchainQueries blockchain;
private final BlockchainQueries blockchainQueries;

public EthGetTransactionReceipt(final BlockchainQueries blockchain) {
this.blockchain = blockchain;
public EthGetTransactionReceipt(final BlockchainQueries blockchainQueries) {
this.blockchainQueries = blockchainQueries;
}

@Override
Expand All @@ -43,9 +43,9 @@ public String getName() {
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
final Hash hash = requestContext.getRequiredParameter(0, Hash.class);
final TransactionReceiptResult result =
blockchain
blockchainQueries
.transactionReceiptByTransactionHash(hash)
.map(receipt -> getResult(receipt))
.map(this::getResult)
.orElse(null);
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), result);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ protected TransactionReceiptResult(final TransactionReceiptWithMetadata receiptW
this.from = txn.getSender().toString();
this.gasUsed = Quantity.create(receiptWithMetadata.getGasUsed());
this.effectiveGasPrice =
Quantity.create(txn.calcEffectiveGas(receiptWithMetadata.getBaseFee()));
Quantity.create(txn.getEffectiveGasPrice(receiptWithMetadata.getBaseFee()));

this.logs =
logReceipts(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.Transaction;
Expand All @@ -37,6 +38,7 @@
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.plugin.data.TransactionType;

import java.math.BigInteger;
import java.util.Collections;
Expand All @@ -47,7 +49,7 @@

public class EthGetTransactionReceiptTest {

private final TransactionReceipt stateReceipt =
private final TransactionReceipt statusReceipt =
new TransactionReceipt(1, 12, Collections.emptyList(), Optional.empty());
private final Hash stateRoot =
Hash.fromHexString("0000000000000000000000000000000000000000000000000000000000000000");
Expand Down Expand Up @@ -76,9 +78,9 @@ public class EthGetTransactionReceiptTest {
private final Hash blockHash =
Hash.fromHexString("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");

private final TransactionReceiptWithMetadata stateReceiptWithMetaData =
private final TransactionReceiptWithMetadata statusReceiptWithMetadata =
TransactionReceiptWithMetadata.create(
stateReceipt, transaction, hash, 1, 2, Optional.empty(), blockHash, 4);
statusReceipt, transaction, hash, 1, 2, Optional.empty(), blockHash, 4);
private final TransactionReceiptWithMetadata rootReceiptWithMetaData =
TransactionReceiptWithMetadata.create(
rootReceipt, transaction, hash, 1, 2, Optional.empty(), blockHash, 4);
Expand Down Expand Up @@ -152,7 +154,7 @@ public class EthGetTransactionReceiptTest {
public void shouldCreateAStatusTransactionReceiptWhenStatusTypeProtocol() {
when(blockchain.headBlockNumber()).thenReturn(1L);
when(blockchain.transactionReceiptByTransactionHash(receiptHash))
.thenReturn(Optional.of(stateReceiptWithMetaData));
.thenReturn(Optional.of(statusReceiptWithMetadata));
when(protocolSchedule.getByBlockNumber(1)).thenReturn(statusTransactionTypeSpec);

final JsonRpcSuccessResponse response =
Expand All @@ -176,4 +178,30 @@ public void shouldCreateARootTransactionReceiptWhenRootTypeProtocol() {

assertThat(result.getRoot()).isEqualTo(stateRoot.toString());
}

@Test
public void shouldWorkFor1559Txs() {
when(blockchain.headBlockNumber()).thenReturn(1L);
final Transaction transaction1559 =
new BlockDataGenerator().transaction(TransactionType.EIP1559);
final long baseFee = 1L;
final TransactionReceiptWithMetadata transactionReceiptWithMetadata =
TransactionReceiptWithMetadata.create(
statusReceipt, transaction1559, hash, 1, 2, Optional.of(baseFee), blockHash, 4);
when(blockchain.transactionReceiptByTransactionHash(receiptHash))
.thenReturn(Optional.of(transactionReceiptWithMetadata));
when(protocolSchedule.getByBlockNumber(1)).thenReturn(rootTransactionTypeSpec);

final JsonRpcSuccessResponse response =
(JsonRpcSuccessResponse) ethGetTransactionReceipt.response(request);
final TransactionReceiptStatusResult result =
(TransactionReceiptStatusResult) response.getResult();

assertThat(result.getStatus()).isEqualTo("0x1");
assertThat(Long.decode(result.getEffectiveGasPrice()))
.isEqualTo(
Math.min(
baseFee + transaction1559.getMaxPriorityFeePerGas().get().toLong(),
transaction1559.getMaxFeePerGas().get().toLong()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1006,22 +1006,7 @@ SECPSignature computeSignature(final KeyPair keys) {
* @param baseFeePerGas optional baseFee from the block header, if we are post-london
* @return the effective gas price.
*/
public final Wei calcEffectiveGas(final Optional<Long> baseFeePerGas) {
return baseFeePerGas
.filter(fee -> getType().supports1559FeeMarket())
.map(BigInteger::valueOf)
.flatMap(
baseFee ->
getMaxFeePerGas()
.map(org.hyperledger.besu.plugin.data.Quantity::getAsBigInteger)
.flatMap(
maxFeePerGas ->
getMaxPriorityFeePerGas()
.map(org.hyperledger.besu.plugin.data.Quantity::getAsBigInteger)
.map(
maxPriorityFeePerGas ->
baseFee.add(maxPriorityFeePerGas).min(maxFeePerGas))))
.map(Wei::ofNumber)
.orElse(getGasPrice().get());
public final Wei getEffectiveGasPrice(final Optional<Long> baseFeePerGas) {
return Wei.of(getEffectivePriorityFeePerGas(baseFeePerGas) + baseFeePerGas.orElse(0L));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -438,8 +438,8 @@ private long suggestGasPrice(final Block block) {
// retrieves transactions from the last blocks and takes the lowest gas price. If no transaction
// is present we return the minTransactionGasPrice of the mining coordinator
return block.getBody().getTransactions().stream()
.min(Comparator.comparing(t -> t.calcEffectiveGas(block.getHeader().getBaseFee())))
.map(t -> t.calcEffectiveGas(block.getHeader().getBaseFee()))
.min(Comparator.comparing(t -> t.getEffectiveGasPrice(block.getHeader().getBaseFee())))
.map(t -> t.getEffectiveGasPrice(block.getHeader().getBaseFee()))
.filter(wei -> wei.getValue().longValue() > 0)
.orElse(miningCoordinator.getMinTransactionGasPrice())
.getValue()
Expand Down

0 comments on commit 375d9b6

Please sign in to comment.