Skip to content

Commit

Permalink
[Interop-4844] Data gas accounting (hyperledger#4998)
Browse files Browse the repository at this point in the history
merge of hyperledger#4992 into interop feature branch

Signed-off-by: Fabio Di Fabio <[email protected]>
(cherry picked from commit 949e3fe)
(cherry picked from commit 9734c983ce00bda161434506688f12ee07bbd820)
Signed-off-by: Gabriel-Trintinalia <[email protected]>
  • Loading branch information
fab-10 authored and jflo committed Jul 19, 2023
1 parent 38febfc commit fe5c499
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 156 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.hyperledger.besu.datatypes.DataGas;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.GasLimitCalculator;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.BlockTransactionSelector.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.core.Block;
Expand Down Expand Up @@ -232,6 +233,10 @@ protected BlockCreationResult createBlock(

throwIfStopped();

final DataGas newExcessDataGas = computeExcessDataGas(transactionResults, newProtocolSpec);

throwIfStopped();

final SealableBlockHeader sealableBlockHeader =
BlockHeaderBuilder.create()
.populateFrom(processableBlockHeader)
Expand Down Expand Up @@ -362,13 +367,13 @@ private ProcessableBlockHeader createPendingBlockHeader(
final Optional<Bytes32> maybePrevRandao,
final ProtocolSpec protocolSpec) {
final long newBlockNumber = parentHeader.getNumber() + 1;
long gasLimit =
protocolSpec
.getGasLimitCalculator()
.nextGasLimit(
parentHeader.getGasLimit(),
targetGasLimitSupplier.get().orElse(parentHeader.getGasLimit()),
newBlockNumber);
final GasLimitCalculator gasLimitCalculator = protocolSpec.getGasLimitCalculator();

final long gasLimit =
gasLimitCalculator.nextGasLimit(
parentHeader.getGasLimit(),
targetGasLimitSupplier.get().orElse(parentHeader.getGasLimit()),
newBlockNumber);

final DifficultyCalculator difficultyCalculator = protocolSpec.getDifficultyCalculator();
final BigInteger difficulty =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,17 @@
import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.account.EvmAccount;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
import org.hyperledger.besu.plugin.data.TransactionType;
import org.hyperledger.besu.plugin.services.txselection.TransactionSelector;
import org.hyperledger.besu.plugin.services.txselection.TransactionSelectorFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
Expand All @@ -51,6 +55,7 @@
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.google.common.collect.Lists;
import org.slf4j.Logger;
Expand All @@ -77,136 +82,6 @@
* not cleared between executions of buildTransactionListForBlock().
*/
public class BlockTransactionSelector {
public static class TransactionValidationResult {
private final Transaction transaction;
private final ValidationResult<TransactionInvalidReason> validationResult;

public TransactionValidationResult(
final Transaction transaction,
final ValidationResult<TransactionInvalidReason> validationResult) {
this.transaction = transaction;
this.validationResult = validationResult;
}

public Transaction getTransaction() {
return transaction;
}

public ValidationResult<TransactionInvalidReason> getValidationResult() {
return validationResult;
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TransactionValidationResult that = (TransactionValidationResult) o;
return Objects.equals(transaction, that.transaction)
&& Objects.equals(validationResult, that.validationResult);
}

@Override
public int hashCode() {
return Objects.hash(transaction, validationResult);
}
}

public static class TransactionSelectionResults {
private final List<Transaction> transactions = Lists.newArrayList();
private final Map<TransactionType, List<Transaction>> transactionsByType =
new EnumMap<>(TransactionType.class);
private final List<TransactionReceipt> receipts = Lists.newArrayList();
private final List<TransactionValidationResult> invalidTransactions = Lists.newArrayList();
private long cumulativeGasUsed = 0;
private long cumulativeDataGasUsed = 0;

private void update(
final Transaction transaction,
final TransactionReceipt receipt,
final long gasUsed,
final long dataGasUsed) {
transactions.add(transaction);
transactionsByType
.computeIfAbsent(transaction.getType(), type -> new ArrayList<>())
.add(transaction);
receipts.add(receipt);
cumulativeGasUsed += gasUsed;
cumulativeDataGasUsed += dataGasUsed;
LOG.atTrace()
.setMessage(
"New selected transaction {}, total transactions {}, cumulative gas used {}, cumulative data gas used {}")
.addArgument(transaction::toTraceLog)
.addArgument(transactions::size)
.addArgument(cumulativeGasUsed)
.addArgument(cumulativeDataGasUsed)
.log();
}

private void updateWithInvalidTransaction(
final Transaction transaction,
final ValidationResult<TransactionInvalidReason> validationResult) {
invalidTransactions.add(new TransactionValidationResult(transaction, validationResult));
}

public List<Transaction> getTransactions() {
return transactions;
}

public List<Transaction> getTransactionsByType(final TransactionType type) {
return transactionsByType.getOrDefault(type, List.of());
}

public List<TransactionReceipt> getReceipts() {
return receipts;
}

public long getCumulativeGasUsed() {
return cumulativeGasUsed;
}

public long getCumulativeDataGasUsed() {
return cumulativeDataGasUsed;
}

public List<TransactionValidationResult> getInvalidTransactions() {
return invalidTransactions;
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TransactionSelectionResults that = (TransactionSelectionResults) o;
return cumulativeGasUsed == that.cumulativeGasUsed
&& cumulativeDataGasUsed == that.cumulativeDataGasUsed
&& transactions.equals(that.transactions)
&& receipts.equals(that.receipts)
&& invalidTransactions.equals(that.invalidTransactions);
}

@Override
public int hashCode() {
return Objects.hash(
transactions, receipts, invalidTransactions, cumulativeGasUsed, cumulativeDataGasUsed);
}

public String toTraceLog() {
return "cumulativeGasUsed="
+ cumulativeGasUsed
+ ", cumulativeDataGasUsed="
+ cumulativeDataGasUsed
+ ", transactions="
+ transactions.stream().map(Transaction::toTraceLog).collect(Collectors.joining("; "));
}
}

private static final Logger LOG = LoggerFactory.getLogger(BlockTransactionSelector.class);

Expand Down Expand Up @@ -404,7 +279,13 @@ private List<org.hyperledger.besu.plugin.data.Log> getLogs(final List<Log> logs)

private boolean transactionDataPriceBelowMin(final Transaction transaction) {
if (transaction.getType().supportsBlob()) {
if (transaction.getMaxFeePerDataGas().orElseThrow().lessThan(dataGasPrice)) {
if (transaction
.getMaxFeePerDataGas()
.orElseThrow()
.lessThan(
feeMarket
.getTransactionPriceCalculator()
.dataPrice(transaction, processableBlockHeader))) {
return true;
}
}
Expand Down Expand Up @@ -474,7 +355,6 @@ private void updateTransactionResultTracking(
final Transaction transaction, final TransactionProcessingResult result) {

final long gasUsedByTransaction = transaction.getGasLimit() - result.getGasRemaining();

final long cumulativeGasUsed =
transactionSelectionResult.getCumulativeGasUsed() + gasUsedByTransaction;

Expand Down Expand Up @@ -522,4 +402,140 @@ private boolean blockOccupancyAboveThreshold() {

return occupancyRatio >= minBlockOccupancyRatio;
}

public static class TransactionValidationResult {
private final Transaction transaction;
private final ValidationResult<TransactionInvalidReason> validationResult;

public TransactionValidationResult(
final Transaction transaction,
final ValidationResult<TransactionInvalidReason> validationResult) {
this.transaction = transaction;
this.validationResult = validationResult;
}

public Transaction getTransaction() {
return transaction;
}

public ValidationResult<TransactionInvalidReason> getValidationResult() {
return validationResult;
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TransactionValidationResult that = (TransactionValidationResult) o;
return Objects.equals(transaction, that.transaction)
&& Objects.equals(validationResult, that.validationResult);
}

@Override
public int hashCode() {
return Objects.hash(transaction, validationResult);
}
}

public static class TransactionSelectionResults {

private final Map<TransactionType, List<Transaction>> transactionsByType = new HashMap<>();
private final List<TransactionReceipt> receipts = Lists.newArrayList();
private final List<TransactionValidationResult> invalidTransactions = Lists.newArrayList();
private long cumulativeGasUsed = 0;
private long cumulativeDataGasUsed = 0;

private void update(
final Transaction transaction,
final TransactionReceipt receipt,
final long gasUsed,
final long dataGasUsed) {
transactionsByType
.computeIfAbsent(transaction.getType(), type -> new ArrayList<>())
.add(transaction);
receipts.add(receipt);
cumulativeGasUsed += gasUsed;
cumulativeDataGasUsed += dataGasUsed;
traceLambda(
LOG,
"New selected transaction {}, total transactions {}, cumulative gas used {}, cumulative data gas used {}",
transaction::toTraceLog,
() -> transactionsByType.values().stream().mapToInt(List::size).sum(),
() -> cumulativeGasUsed,
() -> cumulativeDataGasUsed);
}

private void updateWithInvalidTransaction(
final Transaction transaction,
final ValidationResult<TransactionInvalidReason> validationResult) {
invalidTransactions.add(new TransactionValidationResult(transaction, validationResult));
}

public List<Transaction> getTransactions() {
return streamAllTransactions().collect(Collectors.toList());
}

public List<Transaction> getTransactionsByType(final TransactionType type) {
return transactionsByType.getOrDefault(type, List.of());
}

public List<TransactionReceipt> getReceipts() {
return receipts;
}

public long getCumulativeGasUsed() {
return cumulativeGasUsed;
}

public long getCumulativeDataGasUsed() {
return cumulativeDataGasUsed;
}

public List<TransactionValidationResult> getInvalidTransactions() {
return invalidTransactions;
}

private Stream<Transaction> streamAllTransactions() {
return transactionsByType.values().stream().flatMap(List::stream);
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TransactionSelectionResults that = (TransactionSelectionResults) o;
return cumulativeGasUsed == that.cumulativeGasUsed
&& cumulativeDataGasUsed == that.cumulativeDataGasUsed
&& transactionsByType.equals(that.transactionsByType)
&& receipts.equals(that.receipts)
&& invalidTransactions.equals(that.invalidTransactions);
}

@Override
public int hashCode() {
return Objects.hash(
transactionsByType,
receipts,
invalidTransactions,
cumulativeGasUsed,
cumulativeDataGasUsed);
}

public String toTraceLog() {
return "cumulativeGasUsed="
+ cumulativeGasUsed
+ ", cumulativeDataGasUsed="
+ cumulativeDataGasUsed
+ ", transactions="
+ streamAllTransactions().map(Transaction::toTraceLog).collect(Collectors.joining("; "));
}
}
}
Loading

0 comments on commit fe5c499

Please sign in to comment.