Skip to content

Commit 82b8219

Browse files
fab-10jflo
authored andcommitted
[Interop-4844] Data gas accounting (#4998)
merge of #4992 into interop feature branch Signed-off-by: Fabio Di Fabio <[email protected]> (cherry picked from commit 949e3fe) (cherry picked from commit 9734c983ce00bda161434506688f12ee07bbd820)
1 parent d0406c3 commit 82b8219

File tree

12 files changed

+297
-175
lines changed

12 files changed

+297
-175
lines changed

ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.hyperledger.besu.datatypes.DataGas;
1919
import org.hyperledger.besu.datatypes.Hash;
2020
import org.hyperledger.besu.datatypes.Wei;
21+
import org.hyperledger.besu.ethereum.GasLimitCalculator;
2122
import org.hyperledger.besu.ethereum.ProtocolContext;
2223
import org.hyperledger.besu.ethereum.blockcreation.BlockTransactionSelector.TransactionSelectionResults;
2324
import org.hyperledger.besu.ethereum.core.Block;
@@ -232,6 +233,10 @@ protected BlockCreationResult createBlock(
232233

233234
throwIfStopped();
234235

236+
final DataGas newExcessDataGas = computeExcessDataGas(transactionResults, newProtocolSpec);
237+
238+
throwIfStopped();
239+
235240
final SealableBlockHeader sealableBlockHeader =
236241
BlockHeaderBuilder.create()
237242
.populateFrom(processableBlockHeader)
@@ -362,13 +367,13 @@ private ProcessableBlockHeader createPendingBlockHeader(
362367
final Optional<Bytes32> maybePrevRandao,
363368
final ProtocolSpec protocolSpec) {
364369
final long newBlockNumber = parentHeader.getNumber() + 1;
365-
long gasLimit =
366-
protocolSpec
367-
.getGasLimitCalculator()
368-
.nextGasLimit(
369-
parentHeader.getGasLimit(),
370-
targetGasLimitSupplier.get().orElse(parentHeader.getGasLimit()),
371-
newBlockNumber);
370+
final GasLimitCalculator gasLimitCalculator = protocolSpec.getGasLimitCalculator();
371+
372+
final long gasLimit =
373+
gasLimitCalculator.nextGasLimit(
374+
parentHeader.getGasLimit(),
375+
targetGasLimitSupplier.get().orElse(parentHeader.getGasLimit()),
376+
newBlockNumber);
372377

373378
final DifficultyCalculator difficultyCalculator = protocolSpec.getDifficultyCalculator();
374379
final BigInteger difficulty =

ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java

Lines changed: 164 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,17 @@
3434
import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
3535
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
3636
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
37-
import org.hyperledger.besu.evm.log.Log;
37+
import org.hyperledger.besu.evm.account.EvmAccount;
38+
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
3839
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
3940
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
4041
import org.hyperledger.besu.plugin.data.TransactionType;
4142
import org.hyperledger.besu.plugin.services.txselection.TransactionSelector;
4243
import org.hyperledger.besu.plugin.services.txselection.TransactionSelectorFactory;
4344

4445
import java.util.ArrayList;
46+
import java.util.Collections;
47+
import java.util.HashMap;
4548
import java.util.EnumMap;
4649
import java.util.List;
4750
import java.util.Map;
@@ -51,6 +54,7 @@
5154
import java.util.function.Function;
5255
import java.util.function.Supplier;
5356
import java.util.stream.Collectors;
57+
import java.util.stream.Stream;
5458

5559
import com.google.common.collect.Lists;
5660
import org.slf4j.Logger;
@@ -78,138 +82,6 @@
7882
*/
7983
public class BlockTransactionSelector {
8084

81-
public record TransactionValidationResult(
82-
Transaction transaction, ValidationResult<TransactionInvalidReason> validationResult) {}
83-
84-
public static class TransactionSelectionResults {
85-
private final List<Transaction> transactions = Lists.newArrayList();
86-
private final Map<TransactionType, List<Transaction>> transactionsByType =
87-
new EnumMap<>(TransactionType.class);
88-
private final List<TransactionReceipt> receipts = Lists.newArrayList();
89-
private final List<TransactionValidationResult> invalidTransactions = Lists.newArrayList();
90-
private final List<TransactionSelectionResult> selectionResults = Lists.newArrayList();
91-
private long cumulativeGasUsed = 0;
92-
private long cumulativeDataGasUsed = 0;
93-
94-
private void update(
95-
final Transaction transaction,
96-
final TransactionReceipt receipt,
97-
final long gasUsed,
98-
final long dataGasUsed) {
99-
transactions.add(transaction);
100-
transactionsByType
101-
.computeIfAbsent(transaction.getType(), type -> new ArrayList<>())
102-
.add(transaction);
103-
receipts.add(receipt);
104-
cumulativeGasUsed += gasUsed;
105-
cumulativeDataGasUsed += dataGasUsed;
106-
LOG.atTrace()
107-
.setMessage(
108-
"New selected transaction {}, total transactions {}, cumulative gas used {}, cumulative data gas used {}")
109-
.addArgument(transaction::toTraceLog)
110-
.addArgument(transactions::size)
111-
.addArgument(cumulativeGasUsed)
112-
.addArgument(cumulativeDataGasUsed)
113-
.log();
114-
}
115-
116-
private void updateWithInvalidTransaction(
117-
final Transaction transaction,
118-
final ValidationResult<TransactionInvalidReason> validationResult) {
119-
invalidTransactions.add(new TransactionValidationResult(transaction, validationResult));
120-
}
121-
122-
public List<Transaction> getTransactions() {
123-
return transactions;
124-
}
125-
126-
public List<Transaction> getTransactionsByType(final TransactionType type) {
127-
return transactionsByType.getOrDefault(type, List.of());
128-
}
129-
130-
public List<TransactionReceipt> getReceipts() {
131-
return receipts;
132-
}
133-
134-
public long getCumulativeGasUsed() {
135-
return cumulativeGasUsed;
136-
}
137-
138-
public long getCumulativeDataGasUsed() {
139-
return cumulativeDataGasUsed;
140-
}
141-
142-
public List<TransactionValidationResult> getInvalidTransactions() {
143-
return invalidTransactions;
144-
}
145-
146-
public void addSelectionResult(final TransactionSelectionResult res) {
147-
selectionResults.add(res);
148-
}
149-
150-
public void logSelectionStats() {
151-
if (LOG.isDebugEnabled()) {
152-
final Map<TransactionSelectionResult, Long> selectionStats =
153-
selectionResults.stream()
154-
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
155-
156-
LOG.debug(
157-
"Selection stats: Totals[Evaluated={}, Selected={}, Skipped={}, Dropped={}]; Detailed[{}]",
158-
selectionResults.size(),
159-
selectionStats.entrySet().stream()
160-
.filter(e -> e.getKey().selected())
161-
.map(Map.Entry::getValue)
162-
.mapToInt(Long::intValue)
163-
.sum(),
164-
selectionStats.entrySet().stream()
165-
.filter(e -> !e.getKey().selected())
166-
.map(Map.Entry::getValue)
167-
.mapToInt(Long::intValue)
168-
.sum(),
169-
selectionStats.entrySet().stream()
170-
.filter(e -> e.getKey().discard())
171-
.map(Map.Entry::getValue)
172-
.mapToInt(Long::intValue)
173-
.sum(),
174-
selectionStats.entrySet().stream()
175-
.map(e -> e.getKey().toString() + "=" + e.getValue())
176-
.sorted()
177-
.collect(Collectors.joining(", ")));
178-
}
179-
}
180-
181-
@Override
182-
public boolean equals(final Object o) {
183-
if (this == o) {
184-
return true;
185-
}
186-
if (o == null || getClass() != o.getClass()) {
187-
return false;
188-
}
189-
TransactionSelectionResults that = (TransactionSelectionResults) o;
190-
return cumulativeGasUsed == that.cumulativeGasUsed
191-
&& cumulativeDataGasUsed == that.cumulativeDataGasUsed
192-
&& transactions.equals(that.transactions)
193-
&& receipts.equals(that.receipts)
194-
&& invalidTransactions.equals(that.invalidTransactions);
195-
}
196-
197-
@Override
198-
public int hashCode() {
199-
return Objects.hash(
200-
transactions, receipts, invalidTransactions, cumulativeGasUsed, cumulativeDataGasUsed);
201-
}
202-
203-
public String toTraceLog() {
204-
return "cumulativeGasUsed="
205-
+ cumulativeGasUsed
206-
+ ", cumulativeDataGasUsed="
207-
+ cumulativeDataGasUsed
208-
+ ", transactions="
209-
+ transactions.stream().map(Transaction::toTraceLog).collect(Collectors.joining("; "));
210-
}
211-
}
212-
21385
private static final Logger LOG = LoggerFactory.getLogger(BlockTransactionSelector.class);
21486

21587
private final Wei minTransactionGasPrice;
@@ -410,7 +282,13 @@ private List<org.hyperledger.besu.plugin.data.Log> getLogs(final List<Log> logs)
410282

411283
private boolean transactionDataPriceBelowMin(final Transaction transaction) {
412284
if (transaction.getType().supportsBlob()) {
413-
if (transaction.getMaxFeePerDataGas().orElseThrow().lessThan(dataGasPrice)) {
285+
if (transaction
286+
.getMaxFeePerDataGas()
287+
.orElseThrow()
288+
.lessThan(
289+
feeMarket
290+
.getTransactionPriceCalculator()
291+
.dataPrice(transaction, processableBlockHeader))) {
414292
return true;
415293
}
416294
}
@@ -472,6 +350,27 @@ private boolean isTransientValidationError(final TransactionInvalidReason invali
472350
|| invalidReason.equals(TransactionInvalidReason.NONCE_TOO_HIGH);
473351
}
474352

353+
/*
354+
Responsible for updating the state maintained between transaction validation (i.e. receipts,
355+
cumulative gas, world state root hash.).
356+
*/
357+
private void updateTransactionResultTracking(
358+
final Transaction transaction, final TransactionProcessingResult result) {
359+
360+
final long gasUsedByTransaction = transaction.getGasLimit() - result.getGasRemaining();
361+
final long cumulativeGasUsed =
362+
transactionSelectionResult.getCumulativeGasUsed() + gasUsedByTransaction;
363+
364+
final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount());
365+
366+
transactionSelectionResult.update(
367+
transaction,
368+
transactionReceiptFactory.create(
369+
transaction.getType(), result, worldState, cumulativeGasUsed),
370+
gasUsedByTransaction,
371+
dataGasUsed);
372+
}
373+
475374
private boolean isIncorrectNonce(final ValidationResult<TransactionInvalidReason> result) {
476375
return result.getInvalidReason().equals(TransactionInvalidReason.NONCE_TOO_HIGH);
477376
}
@@ -507,19 +406,139 @@ private boolean blockOccupancyAboveThreshold() {
507406
return occupancyRatio >= minBlockOccupancyRatio;
508407
}
509408

510-
private boolean blockFull() {
511-
final long gasAvailable = processableBlockHeader.getGasLimit();
512-
final long gasUsed = transactionSelectionResults.getCumulativeGasUsed();
409+
public static class TransactionValidationResult {
410+
private final Transaction transaction;
411+
private final ValidationResult<TransactionInvalidReason> validationResult;
513412

514-
final long gasRemaining = gasAvailable - gasUsed;
413+
public TransactionValidationResult(
414+
final Transaction transaction,
415+
final ValidationResult<TransactionInvalidReason> validationResult) {
416+
this.transaction = transaction;
417+
this.validationResult = validationResult;
418+
}
515419

516-
if (gasRemaining < gasCalculator.getMinimumTransactionCost()) {
517-
LOG.trace(
518-
"Block full, remaining gas {} is less than minimum transaction gas cost {}",
519-
gasRemaining,
520-
gasCalculator.getMinimumTransactionCost());
521-
return true;
420+
public Transaction getTransaction() {
421+
return transaction;
422+
}
423+
424+
public ValidationResult<TransactionInvalidReason> getValidationResult() {
425+
return validationResult;
426+
}
427+
428+
@Override
429+
public boolean equals(final Object o) {
430+
if (this == o) {
431+
return true;
432+
}
433+
if (o == null || getClass() != o.getClass()) {
434+
return false;
435+
}
436+
TransactionValidationResult that = (TransactionValidationResult) o;
437+
return Objects.equals(transaction, that.transaction)
438+
&& Objects.equals(validationResult, that.validationResult);
439+
}
440+
441+
@Override
442+
public int hashCode() {
443+
return Objects.hash(transaction, validationResult);
444+
}
445+
}
446+
447+
public static class TransactionSelectionResults {
448+
449+
private final Map<TransactionType, List<Transaction>> transactionsByType = new HashMap<>();
450+
private final List<TransactionReceipt> receipts = Lists.newArrayList();
451+
private final List<TransactionValidationResult> invalidTransactions = Lists.newArrayList();
452+
private long cumulativeGasUsed = 0;
453+
private long cumulativeDataGasUsed = 0;
454+
455+
private void update(
456+
final Transaction transaction,
457+
final TransactionReceipt receipt,
458+
final long gasUsed,
459+
final long dataGasUsed) {
460+
transactionsByType
461+
.computeIfAbsent(transaction.getType(), type -> new ArrayList<>())
462+
.add(transaction);
463+
receipts.add(receipt);
464+
cumulativeGasUsed += gasUsed;
465+
cumulativeDataGasUsed += dataGasUsed;
466+
traceLambda(
467+
LOG,
468+
"New selected transaction {}, total transactions {}, cumulative gas used {}, cumulative data gas used {}",
469+
transaction::toTraceLog,
470+
() -> transactionsByType.values().stream().mapToInt(List::size).sum(),
471+
() -> cumulativeGasUsed,
472+
() -> cumulativeDataGasUsed);
473+
}
474+
475+
private void updateWithInvalidTransaction(
476+
final Transaction transaction,
477+
final ValidationResult<TransactionInvalidReason> validationResult) {
478+
invalidTransactions.add(new TransactionValidationResult(transaction, validationResult));
479+
}
480+
481+
public List<Transaction> getTransactions() {
482+
return streamAllTransactions().collect(Collectors.toList());
483+
}
484+
485+
public List<Transaction> getTransactionsByType(final TransactionType type) {
486+
return transactionsByType.getOrDefault(type, List.of());
487+
}
488+
489+
public List<TransactionReceipt> getReceipts() {
490+
return receipts;
491+
}
492+
493+
public long getCumulativeGasUsed() {
494+
return cumulativeGasUsed;
495+
}
496+
497+
public long getCumulativeDataGasUsed() {
498+
return cumulativeDataGasUsed;
499+
}
500+
501+
public List<TransactionValidationResult> getInvalidTransactions() {
502+
return invalidTransactions;
503+
}
504+
505+
private Stream<Transaction> streamAllTransactions() {
506+
return transactionsByType.values().stream().flatMap(List::stream);
507+
}
508+
509+
@Override
510+
public boolean equals(final Object o) {
511+
if (this == o) {
512+
return true;
513+
}
514+
if (o == null || getClass() != o.getClass()) {
515+
return false;
516+
}
517+
TransactionSelectionResults that = (TransactionSelectionResults) o;
518+
return cumulativeGasUsed == that.cumulativeGasUsed
519+
&& cumulativeDataGasUsed == that.cumulativeDataGasUsed
520+
&& transactionsByType.equals(that.transactionsByType)
521+
&& receipts.equals(that.receipts)
522+
&& invalidTransactions.equals(that.invalidTransactions);
523+
}
524+
525+
@Override
526+
public int hashCode() {
527+
return Objects.hash(
528+
transactionsByType,
529+
receipts,
530+
invalidTransactions,
531+
cumulativeGasUsed,
532+
cumulativeDataGasUsed);
533+
}
534+
535+
public String toTraceLog() {
536+
return "cumulativeGasUsed="
537+
+ cumulativeGasUsed
538+
+ ", cumulativeDataGasUsed="
539+
+ cumulativeDataGasUsed
540+
+ ", transactions="
541+
+ streamAllTransactions().map(Transaction::toTraceLog).collect(Collectors.joining("; "));
522542
}
523-
return false;
524543
}
525544
}

0 commit comments

Comments
 (0)