Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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 @@ -21,6 +21,7 @@
- Add IPv6 dual-stack support for DiscV5 peer discovery (enabled via `--Xv5-discovery-enabled`): new `--p2p-host-ipv6`, `--p2p-interface-ipv6`, and `--p2p-port-ipv6` CLI options enable a second UDP discovery socket; `--p2p-ipv6-outbound-enabled` controls whether IPv6 is preferred for outbound connections when a peer advertises both address families [#9763](https://github.com/hyperledger/besu/pull/9763); RLPx now also binds a second TCP socket on the IPv6 interface so IPv6-only peers can establish connections [#9873](https://github.com/hyperledger/besu/pull/9873)
- Stop EngineQosTimer as part of shutdown [#9903](https://github.com/hyperledger/besu/pull/9903)
- Add `--max-blobs-per-transaction` CLI option to configure the maximum number of blobs per transaction [#9912](https://github.com/hyperledger/besu/pull/9912)
- Add `--max-blobs-per-block` CLI option to configure the maximum number of blobs per block when block building [#9983](https://github.com/hyperledger/besu/pull/9983)
- Add blockTimestamp to transaction RPC results [#9887](https://github.com/hyperledger/besu/pull/9887)
- Plugin API: Allow the registration of multiple PluginTransactionPoolValidatorFactory [#9964](https://github.com/hyperledger/besu/pull/9964)

Expand Down
5 changes: 5 additions & 0 deletions app/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -2945,6 +2945,11 @@ private String generateConfigurationOverview() {
.getMaxBlobsPerTransaction()
.ifPresent(v -> builder.setMaxBlobsPerTransaction(v));

miningParametersSupplier
.get()
.getMaxBlobsPerBlock()
.ifPresent(v -> builder.setMaxBlobsPerBlock(v));

builder
.setDiscoveryEnabled(p2PDiscoveryOptions.peerDiscoveryEnabled)
.setSnapServerEnabled(this.unstableSynchronizerOptions.isSnapsyncServerEnabled())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public class ConfigurationOverviewBuilder {
private RocksDBCLIOptions.BlobDBSettings blobDBSettings;
private Long targetGasLimit;
private Integer maxBlobsPerTransaction;
private Integer maxBlobsPerBlock;

/**
* Create a new ConfigurationOverviewBuilder.
Expand Down Expand Up @@ -411,6 +412,17 @@ public ConfigurationOverviewBuilder setMaxBlobsPerTransaction(
return this;
}

/**
* Sets the max blobs per block for block building.
*
* @param maxBlobsPerBlock the max blobs per block
* @return the builder
*/
public ConfigurationOverviewBuilder setMaxBlobsPerBlock(final Integer maxBlobsPerBlock) {
this.maxBlobsPerBlock = maxBlobsPerBlock;
return this;
}

/**
* Sets the chain pruning configuration.
*
Expand Down Expand Up @@ -576,6 +588,10 @@ public String build() {
lines.add("Max Blobs Per Transaction: " + maxBlobsPerTransaction);
}

if (maxBlobsPerBlock != null) {
lines.add("Max Blobs Per Block (builder): " + maxBlobsPerBlock);
}

lines.add("");
lines.add("Host:");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ public class MiningOptions implements CLIOptions<MiningConfiguration> {
arity = "1")
private Integer maxBlobsPerTransaction = null;

@Option(
names = {"--max-blobs-per-block"},
description =
"Maximum number of blobs allowed per block when building blocks. "
+ "Only applies from Osaka hardfork onwards. Must not exceed the protocol maximum. (default: protocol maximum)",
arity = "1")
private Integer maxBlobsPerBlock = null;

@CommandLine.ArgGroup(validate = false)
private final Unstable unstableOptions = new Unstable();

Expand Down Expand Up @@ -234,6 +242,20 @@ public void validate(
throw new ParameterException(
commandLine, "--max-blobs-per-transaction must be a positive value");
}

if (maxBlobsPerBlock != null && maxBlobsPerBlock < 0) {
throw new ParameterException(commandLine, "--max-blobs-per-block must be a positive value");
}

if (maxBlobsPerBlock != null
&& maxBlobsPerTransaction != null
&& maxBlobsPerBlock < maxBlobsPerTransaction) {
logger.warn(
"--max-blobs-per-block ({}) is less than --max-blobs-per-transaction ({}). "
+ "The block limit will be the binding constraint during block building.",
maxBlobsPerBlock,
maxBlobsPerTransaction);
}
}

static MiningOptions fromConfig(final MiningConfiguration miningConfiguration) {
Expand All @@ -253,6 +275,7 @@ static MiningOptions fromConfig(final MiningConfiguration miningConfiguration) {
miningConfiguration
.getMaxBlobsPerTransaction()
.ifPresent(v -> miningOptions.maxBlobsPerTransaction = v);
miningConfiguration.getMaxBlobsPerBlock().ifPresent(v -> miningOptions.maxBlobsPerBlock = v);

miningOptions.unstableOptions.posBlockCreationMaxTime =
miningConfiguration.getUnstable().getPosBlockCreationMaxTime();
Expand Down Expand Up @@ -284,6 +307,10 @@ public MiningConfiguration toDomainObject() {
updatableInitValuesBuilder.maxBlobsPerTransaction(maxBlobsPerTransaction);
}

if (maxBlobsPerBlock != null) {
updatableInitValuesBuilder.maxBlobsPerBlock(maxBlobsPerBlock);
}

if (targetGasLimit != null) {
updatableInitValuesBuilder.targetGasLimit(targetGasLimit);
}
Expand Down
5 changes: 3 additions & 2 deletions app/src/test/resources/everything_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ block-txs-selection-max-time=5000
poa-block-txs-selection-max-time=75
plugin-block-txs-selection-max-time=50
Xpos-block-creation-max-time=5
max-blobs-per-transaction=0
max-blobs-per-transaction=4
max-blobs-per-block=8

# Permissioning
permissions-nodes-config-file-enabled=false
Expand Down Expand Up @@ -252,4 +253,4 @@ snapsync-synchronizer-transaction-indexing-enabled=true
snapsync-synchronizer-pre-checkpoint-headers-only-enabled=true

# history expiry
history-expiry-prune=false
history-expiry-prune=false
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public TransactionSelectionResult evaluateTransactionPreProcessing(
final var cumulativeBlobGasUsed = getWorkingState();

final var remainingBlobGas =
context.gasLimitCalculator().currentBlobGasLimit() - cumulativeBlobGasUsed;
context.gasLimitCalculator().blockBuilderBlobGasLimit() - cumulativeBlobGasUsed;

if (remainingBlobGas == 0) {
LOG.atTrace()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,16 @@ default long transactionGasLimitCap() {
default long transactionBlobGasLimitCap() {
return BLOB_GAS_LIMIT;
}

/**
* Returns the blob gas limit to use when building blocks. This may be lower than {@link
* #currentBlobGasLimit()} when the user has configured {@code --max-blobs-per-block} to
* self-limit block building. Validation of incoming blocks from peers always uses {@link
* #currentBlobGasLimit()}.
*
* @return the blob gas limit for block building
*/
default long blockBuilderBlobGasLimit() {
return currentBlobGasLimit();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,16 @@ public OptionalInt getMaxBlobsPerTransaction() {
return getMutableInitValues().getMaxBlobsPerTransaction();
}

/**
* Returns the maximum blobs per block for block building. Note: Only applies from Osaka hardfork
* onwards. Returns empty if not explicitly set by the user.
*
* @return the maximum blobs per block, or empty if not set
*/
public OptionalInt getMaxBlobsPerBlock() {
return getMutableInitValues().getMaxBlobsPerBlock();
}

public Optional<Iterable<Long>> getNonceGenerator() {
return getMutableRuntimeValues().nonceGenerator;
}
Expand Down Expand Up @@ -269,6 +279,12 @@ default double getMinBlockOccupancyRatio() {
*/
OptionalInt getMaxBlobsPerTransaction();

/**
* Returns the maximum blobs per block for block building. Note: Only applies from Osaka
* hardfork onwards. Empty means use the fork-specific protocol max.
*/
OptionalInt getMaxBlobsPerBlock();

OptionalInt getBlockPeriodSeconds();

OptionalInt getEmptyBlockPeriodSeconds();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1021,7 +1021,8 @@ static ProtocolSpecBuilder osakaDefinition(
gasCalculator,
blobSchedule.getMax(),
blobSchedule.getTarget(),
miningConfiguration.getMaxBlobsPerTransaction()))
miningConfiguration.getMaxBlobsPerTransaction(),
miningConfiguration.getMaxBlobsPerBlock()))
.evmBuilder(
(gasCalculator, __) ->
MainnetEVMs.osaka(gasCalculator, chainId.orElse(BigInteger.ZERO), evmConfiguration))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,18 @@ public class OsakaTargetingGasLimitCalculator extends CancunTargetingGasLimitCal

private final long transactionGasLimitCap;
private final long transactionBlobGasLimitCap;
private final long blockBuilderBlobGasLimit;

public OsakaTargetingGasLimitCalculator(
final long londonForkBlock,
final BaseFeeMarket feeMarket,
final GasCalculator gasCalculator,
final int maxBlobsPerBlock,
final int targetBlobsPerBlock,
final OptionalInt maxBlobsPerTransaction) {
final OptionalInt maxBlobsPerTransaction,
final OptionalInt userMaxBlobsPerBlock) {
super(londonForkBlock, feeMarket, gasCalculator, maxBlobsPerBlock, targetBlobsPerBlock);
final long blobGasPerBlob = gasCalculator.getBlobGasPerBlob();
int effectiveMaxBlobsPerTx = maxBlobsPerTransaction.orElse(DEFAULT_MAX_BLOBS_PER_TRANSACTION);
if (effectiveMaxBlobsPerTx > maxBlobsPerBlock) {
LOG.warn(
Expand All @@ -58,7 +61,13 @@ public OsakaTargetingGasLimitCalculator(
effectiveMaxBlobsPerTx = maxBlobsPerBlock;
}
this.transactionGasLimitCap = DEFAULT_TRANSACTION_GAS_LIMIT_CAP_OSAKA;
this.transactionBlobGasLimitCap = gasCalculator.getBlobGasPerBlob() * effectiveMaxBlobsPerTx;
this.transactionBlobGasLimitCap = blobGasPerBlob * effectiveMaxBlobsPerTx;
if (userMaxBlobsPerBlock.isPresent()) {
final int userMax = userMaxBlobsPerBlock.getAsInt();
this.blockBuilderBlobGasLimit = Math.min(blobGasPerBlob * userMax, getMaxBlobGasPerBlock());
} else {
this.blockBuilderBlobGasLimit = getMaxBlobGasPerBlock();
}
}

@Override
Expand Down Expand Up @@ -100,4 +109,9 @@ public long computeExcessBlobGas(
public long transactionBlobGasLimitCap() {
return transactionBlobGasLimitCap;
}

@Override
public long blockBuilderBlobGasLimit() {
return blockBuilderBlobGasLimit;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ void shouldCalculateCorrectlyPragueBlobGasPerBlob() {
osakaGasCalculator,
BlobSchedule.PRAGUE_DEFAULT.getMax(),
newTargetCount,
OptionalInt.empty(),
OptionalInt.empty());

private static final long TARGET_BLOB_GAS_PER_BLOCK_OSAKA = 0x120000;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ public void shouldSupportTransactionGasLimitCap_EIP_7825(
createTransactionValidator(
gasCalculator,
new OsakaTargetingGasLimitCalculator(
0L, feeMarket, gasCalculator, 6, 3, OptionalInt.of(6)),
0L, feeMarket, gasCalculator, 6, 3, OptionalInt.of(6), OptionalInt.empty()),
feeMarket,
false,
Optional.of(BigInteger.ONE),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ public void shouldCalculateOsakaExcessBlobGasCorrectly(
int targetBlobs = 9;
final OsakaTargetingGasLimitCalculator osakaTargetingGasLimitCalculator =
new OsakaTargetingGasLimitCalculator(
0L, feeMarket, osakaGasCalculator, maxBlobs, targetBlobs, OptionalInt.empty());
0L,
feeMarket,
osakaGasCalculator,
maxBlobs,
targetBlobs,
OptionalInt.empty(),
OptionalInt.empty());

final long usedBlobGas = osakaGasCalculator.blobGasCost(used);
assertThat(
Expand Down Expand Up @@ -91,7 +97,13 @@ void shouldUseCorrectBlobGasPerBlob() {
int targetBlobs = 9;
var osakaTargetingGasLimitCalculator =
new OsakaTargetingGasLimitCalculator(
0L, feeMarket, osakaGasCalculator, maxBlobs, targetBlobs, OptionalInt.empty());
0L,
feeMarket,
osakaGasCalculator,
maxBlobs,
targetBlobs,
OptionalInt.empty(),
OptionalInt.empty());

// if maxBlobs = 10, then the gas limit would be 131072 * 10 = 1310720
assertThat(osakaTargetingGasLimitCalculator.currentBlobGasLimit())
Expand All @@ -108,7 +120,13 @@ void testComputeExcessBlobGasWithDifferentConditions() {
int targetBlobs = 9;
var calculator =
new OsakaTargetingGasLimitCalculator(
0L, feeMarket, osakaGasCalculator, maxBlobs, targetBlobs, OptionalInt.empty());
0L,
feeMarket,
osakaGasCalculator,
maxBlobs,
targetBlobs,
OptionalInt.empty(),
OptionalInt.empty());
assertThat(calculator.maxBlobsPerBlock).isEqualTo(maxBlobs);
assertThat(calculator.targetBlobsPerBlock).isEqualTo(targetBlobs);

Expand Down Expand Up @@ -136,7 +154,13 @@ void osakaBlobGasLimitPerTransaction() {
int targetBlobs = 9;
var calculator =
new OsakaTargetingGasLimitCalculator(
0L, feeMarket, osakaGasCalculator, maxBlobs, targetBlobs, OptionalInt.empty());
0L,
feeMarket,
osakaGasCalculator,
maxBlobs,
targetBlobs,
OptionalInt.empty(),
OptionalInt.empty());
assertThat(calculator.transactionBlobGasLimitCap()).isEqualTo(0xC0000); // 6 * 131072
}

Expand All @@ -152,7 +176,8 @@ void osakaBlobGasLimitPerTransactionWithCustomValue() {
osakaGasCalculator,
maxBlobs,
targetBlobs,
OptionalInt.of(customMaxBlobsPerTx));
OptionalInt.of(customMaxBlobsPerTx),
OptionalInt.empty());
// 3 * 131072 = 393216
assertThat(calculator.transactionBlobGasLimitCap())
.isEqualTo(osakaGasCalculator.getBlobGasPerBlob() * customMaxBlobsPerTx);
Expand All @@ -170,12 +195,66 @@ void maxBlobsPerTransactionClampedToMaxBlobsPerBlock() {
osakaGasCalculator,
maxBlobsPerBlock,
targetBlobs,
OptionalInt.of(tooManyBlobsPerTx));
OptionalInt.of(tooManyBlobsPerTx),
OptionalInt.empty());
// Should be clamped to maxBlobsPerBlock (10), not the user value (15)
assertThat(calculator.transactionBlobGasLimitCap())
.isEqualTo(osakaGasCalculator.getBlobGasPerBlob() * maxBlobsPerBlock);
}

@Test
void blockBuilderBlobGasLimitDefaultsToProtocolMax() {
int maxBlobs = 9;
int targetBlobs = 6;
var calculator =
new OsakaTargetingGasLimitCalculator(
0L,
feeMarket,
osakaGasCalculator,
maxBlobs,
targetBlobs,
OptionalInt.empty(),
OptionalInt.empty());
assertThat(calculator.blockBuilderBlobGasLimit())
.isEqualTo(osakaGasCalculator.getBlobGasPerBlob() * maxBlobs);
}

@Test
void blockBuilderBlobGasLimitRespectedWhenUserConfigured() {
int maxBlobs = 9;
int targetBlobs = 6;
int userMaxBlobs = 3;
var calculator =
new OsakaTargetingGasLimitCalculator(
0L,
feeMarket,
osakaGasCalculator,
maxBlobs,
targetBlobs,
OptionalInt.empty(),
OptionalInt.of(userMaxBlobs));
assertThat(calculator.blockBuilderBlobGasLimit())
.isEqualTo(osakaGasCalculator.getBlobGasPerBlob() * userMaxBlobs);
}

@Test
void blockBuilderBlobGasLimitClampedToProtocolMax() {
int maxBlobs = 9;
int targetBlobs = 6;
int userMaxBlobs = 20; // exceeds protocol max
var calculator =
new OsakaTargetingGasLimitCalculator(
0L,
feeMarket,
osakaGasCalculator,
maxBlobs,
targetBlobs,
OptionalInt.empty(),
OptionalInt.of(userMaxBlobs));
assertThat(calculator.blockBuilderBlobGasLimit())
.isEqualTo(osakaGasCalculator.getBlobGasPerBlob() * maxBlobs);
}

@Test
void dryRunDetector() {
Assertions.assertThat(true)
Expand Down
Loading