Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix NoSuchElementException in Transaction Receipt Logic #2477

Merged
merged 4 commits into from
Jun 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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