From 7324710ac4a50f285495a9415e1f64a2b85aa8c3 Mon Sep 17 00:00:00 2001 From: Simon Dudley Date: Tue, 12 Mar 2024 11:02:56 +1000 Subject: [PATCH 01/11] [MINOR] Remove unused method (#6713) Signed-off-by: Simon Dudley --- .../besu/ethereum/mainnet/DefaultProtocolSchedule.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java index 9499a7a8064..4c209ac096d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java @@ -54,16 +54,6 @@ protected DefaultProtocolSchedule(final DefaultProtocolSchedule protocolSchedule this.protocolSpecs = protocolSchedule.protocolSpecs; } - public ScheduledProtocolSpec specScheduledForBlock(final ProcessableBlockHeader blockHeader) { - return protocolSpecs.stream() - .filter(s -> s.isOnOrAfterMilestoneBoundary(blockHeader)) - .findFirst() - .orElseThrow( - () -> - new IllegalStateException( - "No protocol spec found for block " + blockHeader.getNumber())); - } - @Override public ProtocolSpec getByBlockHeader(final ProcessableBlockHeader blockHeader) { checkArgument( From b2ca0e9bf97774baba7229449ce29888cf4b6ab2 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Tue, 12 Mar 2024 12:36:42 +1100 Subject: [PATCH 02/11] Add privacy and permissioning services to thread plugin context (#6711) Signed-off-by: Gabriel-Trintinalia --- .../acceptance/dsl/node/ThreadBesuNodeRunner.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java index 1c10f82e3bf..87246069e6d 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java @@ -44,7 +44,9 @@ import org.hyperledger.besu.plugin.data.EnodeURL; import org.hyperledger.besu.plugin.services.BesuConfiguration; import org.hyperledger.besu.plugin.services.BesuEvents; +import org.hyperledger.besu.plugin.services.PermissioningService; import org.hyperledger.besu.plugin.services.PicoCLIOptions; +import org.hyperledger.besu.plugin.services.PrivacyPluginService; import org.hyperledger.besu.plugin.services.RpcEndpointService; import org.hyperledger.besu.plugin.services.SecurityModuleService; import org.hyperledger.besu.plugin.services.StorageService; @@ -56,6 +58,7 @@ import org.hyperledger.besu.services.BesuPluginContextImpl; import org.hyperledger.besu.services.PermissioningServiceImpl; import org.hyperledger.besu.services.PicoCLIOptionsImpl; +import org.hyperledger.besu.services.PrivacyPluginServiceImpl; import org.hyperledger.besu.services.RpcEndpointServiceImpl; import org.hyperledger.besu.services.SecurityModuleServiceImpl; import org.hyperledger.besu.services.StorageServiceImpl; @@ -117,15 +120,16 @@ private BesuPluginContextImpl buildPluginContext( } else { pluginsPath = Path.of(pluginDir); } - besuPluginContext.registerPlugins(pluginsPath); - - commandLine.parseArgs(node.getConfiguration().getExtraCLIOptions().toArray(new String[0])); besuPluginContext.addService(BesuConfiguration.class, commonPluginConfiguration); + besuPluginContext.addService(PermissioningService.class, new PermissioningServiceImpl()); + besuPluginContext.addService(PrivacyPluginService.class, new PrivacyPluginServiceImpl()); + + besuPluginContext.registerPlugins(pluginsPath); + commandLine.parseArgs(node.getConfiguration().getExtraCLIOptions().toArray(new String[0])); // register built-in plugins new RocksDBPlugin().register(besuPluginContext); - return besuPluginContext; } From 8becd5a3a881346cf2e42b32c267e3be5e1a6e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Friedemann=20F=C3=BCrst?= <59653747+friedemannf@users.noreply.github.com> Date: Tue, 12 Mar 2024 03:17:06 +0100 Subject: [PATCH 03/11] Transaction call object to accept both input and data field if equal (#6702) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * relax JsonCallParameter constructor to allow for both input and data being set if equal Signed-off-by: Friedemann Fürst * fix: format Signed-off-by: Friedemann Fürst * add changelog entry Signed-off-by: Friedemann Fürst --------- Signed-off-by: Friedemann Fürst Co-authored-by: Sally MacFarlane --- CHANGELOG.md | 1 + .../fork/frontier/EthCallIntegrationTest.java | 27 +++++++++++++++++++ .../parameters/JsonCallParameter.java | 2 +- ...dWithDifferentInputAndDataAttributes.json} | 4 +-- .../eth_call_withInputAndDataAttribute.json | 22 +++++++++++++++ 5 files changed, 53 insertions(+), 3 deletions(-) rename ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/{eth_call_invalidWithInputAndDataAttribute.json => eth_call_invalidWithDifferentInputAndDataAttributes.json} (90%) create mode 100644 ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_withInputAndDataAttribute.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f984840ad2..84bb34bb178 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - Add blob transaction support to `eth_call` [#6661](https://github.com/hyperledger/besu/pull/6661) - Add blobs to `eth_feeHistory` [#6679](https://github.com/hyperledger/besu/pull/6679) - Refactor and extend `TransactionPoolValidatorService` [#6636](https://github.com/hyperledger/besu/pull/6636) +- Transaction call object to accept both `input` and `data` field simultaneously if they are set to equal values [#6702](https://github.com/hyperledger/besu/pull/6702) ### Bug fixes diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthCallIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthCallIntegrationTest.java index 5fa1c70ae16..14aa15c5c8f 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthCallIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthCallIntegrationTest.java @@ -408,6 +408,33 @@ public void shouldReturnEmptyHashResultForCallWithOnlyToField() { assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); } + @Test + public void shouldReturnSuccessWithInputAndDataFieldSetToSameValue() { + final JsonCallParameter callParameter = + new JsonCallParameter( + Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"), + Address.fromHexString("0x6295ee1b4f6dd65047762f924ecd367c17eabf8f"), + null, + null, + null, + null, + null, + Bytes.fromHexString("0x12a7b914"), + Bytes.fromHexString("0x12a7b914"), + null, + null, + null, + null); + final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); + final JsonRpcResponse expectedResponse = + new JsonRpcSuccessResponse( + null, "0x0000000000000000000000000000000000000000000000000000000000000001"); + + final JsonRpcResponse response = method.response(request); + + assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); + } + private JsonRpcRequestContext requestWithParams(final Object... params) { return new JsonRpcRequestContext(new JsonRpcRequest("2.0", "eth_call", params)); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonCallParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonCallParameter.java index dae98e6896a..b71083a4c38 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonCallParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonCallParameter.java @@ -71,7 +71,7 @@ public JsonCallParameter( Optional.ofNullable(maxFeePerBlobGas), Optional.ofNullable(blobVersionedHashes)); - if (input != null && data != null) { + if (input != null && data != null && !input.equals(data)) { throw new IllegalArgumentException("Only one of 'input' or 'data' should be provided"); } diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_invalidWithInputAndDataAttribute.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_invalidWithDifferentInputAndDataAttributes.json similarity index 90% rename from ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_invalidWithInputAndDataAttribute.json rename to ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_invalidWithDifferentInputAndDataAttributes.json index eda5c99c0bc..309e96df249 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_invalidWithInputAndDataAttribute.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_invalidWithDifferentInputAndDataAttributes.json @@ -8,9 +8,9 @@ "to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f", "from": "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", "input": "0x12a7b914", - "data": "0x12a7b914" + "data": "0x12a7b915" }, - "0x19" + "latest" ] }, "response": { diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_withInputAndDataAttribute.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_withInputAndDataAttribute.json new file mode 100644 index 00000000000..929dbe2ad4f --- /dev/null +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_withInputAndDataAttribute.json @@ -0,0 +1,22 @@ +{ + "request": { + "id": 3, + "jsonrpc": "2.0", + "method": "eth_call", + "params": [ + { + "to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f", + "from": "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "input": "0x12a7b914", + "data": "0x12a7b914" + }, + "0x19" + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 3, + "result": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "statusCode": 200 +} \ No newline at end of file From 246cce41e1da3c587fcb374c46371084b43a066d Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Tue, 12 Mar 2024 13:00:54 +1000 Subject: [PATCH 04/11] eth_call with blobs - added more spec tests (#6687) * added more spec tests Signed-off-by: Sally MacFarlane * fixed typo Signed-off-by: Sally MacFarlane * fixed error message Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane --- .../jsonrpc/eth/eth_call_blob_without_to.json | 22 ++++++++++++++++++ .../eth_call_blob_zero_versioned_hash.json | 23 +++++++++++++++++++ .../mainnet/MainnetTransactionValidator.java | 2 +- 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_blob_without_to.json create mode 100644 ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_blob_zero_versioned_hash.json diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_blob_without_to.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_blob_without_to.json new file mode 100644 index 00000000000..c73c61c04de --- /dev/null +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_blob_without_to.json @@ -0,0 +1,22 @@ +{ + "request": { + "id": 4, + "jsonrpc": "2.0", + "method": "eth_call", + "params": [ + { + "from": "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "data": "0x12a7b914", + "blobVersionedHashes" : ["0x0100000051c8833cfbaf272e62da1285b183b0405357f62b052a4894ffcdaa2d"], + "maxFeePerBlobGas": "0x3b9aca00" + }, + "latest" + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 4, + "error":{"code":-32602,"message":"Invalid transaction type"} + }, + "statusCode": 200 +} \ No newline at end of file diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_blob_zero_versioned_hash.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_blob_zero_versioned_hash.json new file mode 100644 index 00000000000..bf4cb06350a --- /dev/null +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_blob_zero_versioned_hash.json @@ -0,0 +1,23 @@ +{ + "request": { + "id": 4, + "jsonrpc": "2.0", + "method": "eth_call", + "params": [ + { + "to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f", + "from": "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "data": "0x12a7b914", + "blobVersionedHashes" : ["0x0"], + "maxFeePerBlobGas": "0x3b9aca00" + }, + "latest" + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 4, + "error":{"code":-32602,"message":"Invalid params"} + }, + "statusCode": 200 +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java index 1e8c620ad16..68eebe5e47c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java @@ -304,7 +304,7 @@ public ValidationResult validateBlobTransaction( if (transaction.getType().supportsBlob() && transaction.getTo().isEmpty()) { return ValidationResult.invalid( TransactionInvalidReason.INVALID_TRANSACTION_FORMAT, - "transaction blob transactions cannot have a to address"); + "transaction blob transactions must have a to address"); } if (transaction.getVersionedHashes().isEmpty()) { From 65f8880fb7dd94df30ce829af1f5bd7106e44c2b Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 12 Mar 2024 10:56:46 +0100 Subject: [PATCH 05/11] Make block txs selection max time aware of PoA transitions (#6676) Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../org/hyperledger/besu/cli/BesuCommand.java | 4 +- .../besu/cli/options/MiningOptions.java | 17 -- .../CliqueBesuControllerBuilder.java | 12 + .../controller/IbftBesuControllerBuilder.java | 11 + .../controller/QbftBesuControllerBuilder.java | 11 + .../cli/options/AbstractCLIOptionsTest.java | 11 +- .../besu/cli/options/MiningOptionsTest.java | 23 +- .../AbstractBftBesuControllerBuilderTest.java | 204 ++++++++++++++++ .../CliqueBesuControllerBuilderTest.java | 231 ++++++++++++++++++ .../IbftBesuControllerBuilderTest.java | 73 ++++++ .../QbftBesuControllerBuilderTest.java | 158 +++--------- .../CliqueBlockSchedulerTest.java | 1 - .../AbstractBlockTransactionSelectorTest.java | 2 +- .../besu/ethereum/core/MiningParameters.java | 29 ++- 15 files changed, 627 insertions(+), 161 deletions(-) create mode 100644 besu/src/test/java/org/hyperledger/besu/controller/AbstractBftBesuControllerBuilderTest.java create mode 100644 besu/src/test/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilderTest.java create mode 100644 besu/src/test/java/org/hyperledger/besu/controller/IbftBesuControllerBuilderTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 84bb34bb178..2ceaa5b1b50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - Transaction call object to accept both `input` and `data` field simultaneously if they are set to equal values [#6702](https://github.com/hyperledger/besu/pull/6702) ### Bug fixes +- Make block transaction selection max time aware of PoA transitions [#6676](https://github.com/hyperledger/besu/pull/6676) ### Download Links diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 679bfc88dd7..6709608834e 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -2149,10 +2149,10 @@ private TransactionPoolConfiguration buildTransactionPoolConfiguration() { private MiningParameters getMiningParameters() { if (miningParameters == null) { - miningOptions.setGenesisBlockPeriodSeconds( - getGenesisBlockPeriodSeconds(getActualGenesisConfigOptions())); miningOptions.setTransactionSelectionService(transactionSelectionServiceImpl); miningParameters = miningOptions.toDomainObject(); + getGenesisBlockPeriodSeconds(getActualGenesisConfigOptions()) + .ifPresent(miningParameters::setBlockPeriodSeconds); initMiningParametersMetrics(miningParameters); } return miningParameters; diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/MiningOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/MiningOptions.java index 976be808495..bcde10077bb 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/MiningOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/MiningOptions.java @@ -42,7 +42,6 @@ import org.hyperledger.besu.util.number.PositiveNumber; import java.util.List; -import java.util.OptionalInt; import org.apache.tuweni.bytes.Bytes; import org.slf4j.Logger; @@ -191,7 +190,6 @@ static class Unstable { DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; } - private OptionalInt maybeGenesisBlockPeriodSeconds; private TransactionSelectionService transactionSelectionService; private MiningOptions() {} @@ -205,16 +203,6 @@ public static MiningOptions create() { return new MiningOptions(); } - /** - * Set the optional genesis block period per seconds - * - * @param genesisBlockPeriodSeconds if the network is PoA then the block period in seconds - * specified in the genesis file, otherwise empty. - */ - public void setGenesisBlockPeriodSeconds(final OptionalInt genesisBlockPeriodSeconds) { - maybeGenesisBlockPeriodSeconds = genesisBlockPeriodSeconds; - } - /** * Set the transaction selection service * @@ -311,7 +299,6 @@ public void validate( static MiningOptions fromConfig(final MiningParameters miningParameters) { final MiningOptions miningOptions = MiningOptions.create(); - miningOptions.setGenesisBlockPeriodSeconds(miningParameters.getGenesisBlockPeriodSeconds()); miningOptions.setTransactionSelectionService(miningParameters.getTransactionSelectionService()); miningOptions.isMiningEnabled = miningParameters.isMiningEnabled(); miningOptions.iStratumMiningEnabled = miningParameters.isStratumMiningEnabled(); @@ -347,9 +334,6 @@ static MiningOptions fromConfig(final MiningParameters miningParameters) { @Override public MiningParameters toDomainObject() { - checkNotNull( - maybeGenesisBlockPeriodSeconds, - "genesisBlockPeriodSeconds must be set before using this object"); checkNotNull( transactionSelectionService, "transactionSelectionService must be set before using this object"); @@ -370,7 +354,6 @@ public MiningParameters toDomainObject() { } return ImmutableMiningParameters.builder() - .genesisBlockPeriodSeconds(maybeGenesisBlockPeriodSeconds) .transactionSelectionService(transactionSelectionService) .mutableInitValues(updatableInitValuesBuilder.build()) .isStratumMiningEnabled(iStratumMiningEnabled) diff --git a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java index 3fe170983a2..88a675d4f10 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java @@ -102,6 +102,18 @@ protected MiningCoordinator createMiningCoordinator( miningExecutor, syncState, new CliqueMiningTracker(localAddress, protocolContext)); + + // Update the next block period in seconds according to the transition schedule + protocolContext + .getBlockchain() + .observeBlockAdded( + o -> + miningParameters.setBlockPeriodSeconds( + forksSchedule + .getFork(o.getBlock().getHeader().getNumber() + 1) + .getValue() + .getBlockPeriodSeconds())); + miningCoordinator.addMinedBlockObserver(ethProtocolManager); // Clique mining is implicitly enabled. diff --git a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java index d191f034596..eb261ff42ba 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java @@ -234,6 +234,17 @@ protected MiningCoordinator createMiningCoordinator( blockchain, bftEventQueue); + // Update the next block period in seconds according to the transition schedule + protocolContext + .getBlockchain() + .observeBlockAdded( + o -> + miningParameters.setBlockPeriodSeconds( + forksSchedule + .getFork(o.getBlock().getHeader().getNumber() + 1) + .getValue() + .getBlockPeriodSeconds())); + if (syncState.isInitialSyncPhaseDone()) { LOG.info("Starting IBFT mining coordinator"); ibftMiningCoordinator.enable(); diff --git a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java index 93b0ea55d84..b26088e73f1 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java @@ -274,6 +274,17 @@ protected MiningCoordinator createMiningCoordinator( blockchain, bftEventQueue); + // Update the next block period in seconds according to the transition schedule + protocolContext + .getBlockchain() + .observeBlockAdded( + o -> + miningParameters.setBlockPeriodSeconds( + qbftForksSchedule + .getFork(o.getBlock().getHeader().getNumber() + 1) + .getValue() + .getBlockPeriodSeconds())); + if (syncState.isInitialSyncPhaseDone()) { LOG.info("Starting QBFT mining coordinator"); miningCoordinator.enable(); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java index 21d8baf9ee9..1760b957ec6 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.List; +import java.util.function.BiFunction; import java.util.function.Consumer; import org.junit.jupiter.api.Test; @@ -113,10 +114,18 @@ protected List getFieldsToIgnore() { protected abstract T getOptionsFromBesuCommand(final TestBesuCommand besuCommand); protected void internalTestSuccess(final Consumer assertion, final String... args) { + internalTestSuccess((bc, conf) -> conf, assertion, args); + } + + protected void internalTestSuccess( + final BiFunction runtimeConf, + final Consumer assertion, + final String... args) { final TestBesuCommand cmd = parseCommand(args); final T options = getOptionsFromBesuCommand(cmd); - final D config = options.toDomainObject(); + final D config = runtimeConf.apply(cmd, options.toDomainObject()); + assertion.accept(config); assertThat(commandOutput.toString(UTF_8)).isEmpty(); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/MiningOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/MiningOptionsTest.java index fda642d6ead..55777e16d42 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/MiningOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/MiningOptionsTest.java @@ -34,7 +34,6 @@ import java.nio.file.Path; import java.time.Duration; import java.util.Optional; -import java.util.OptionalInt; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.Test; @@ -316,6 +315,7 @@ public void posBlockCreationMaxTimeOutOfAllowedRange() { @Test public void blockTxsSelectionMaxTimeDefaultValue() { internalTestSuccess( + this::runtimeConfiguration, miningParams -> assertThat(miningParams.getNonPoaBlockTxsSelectionMaxTime()) .isEqualTo(DEFAULT_NON_POA_BLOCK_TXS_SELECTION_MAX_TIME)); @@ -324,6 +324,7 @@ public void blockTxsSelectionMaxTimeDefaultValue() { @Test public void blockTxsSelectionMaxTimeOption() { internalTestSuccess( + this::runtimeConfiguration, miningParams -> assertThat(miningParams.getBlockTxsSelectionMaxTime()).isEqualTo(1700L), "--block-txs-selection-max-time", "1700"); @@ -343,6 +344,7 @@ public void blockTxsSelectionMaxTimeIncompatibleWithPoaNetworks() throws IOExcep @Test public void poaBlockTxsSelectionMaxTimeDefaultValue() { internalTestSuccess( + this::runtimeConfiguration, miningParams -> assertThat(miningParams.getPoaBlockTxsSelectionMaxTime()) .isEqualTo(DEFAULT_POA_BLOCK_TXS_SELECTION_MAX_TIME)); @@ -352,6 +354,7 @@ public void poaBlockTxsSelectionMaxTimeDefaultValue() { public void poaBlockTxsSelectionMaxTimeOption() throws IOException { final Path genesisFileIBFT2 = createFakeGenesisFile(VALID_GENESIS_IBFT2_POST_LONDON); internalTestSuccess( + this::runtimeConfiguration, miningParams -> assertThat(miningParams.getPoaBlockTxsSelectionMaxTime()) .isEqualTo(PositiveNumber.fromInt(80)), @@ -365,6 +368,7 @@ public void poaBlockTxsSelectionMaxTimeOption() throws IOException { public void poaBlockTxsSelectionMaxTimeOptionOver100Percent() throws IOException { final Path genesisFileClique = createFakeGenesisFile(VALID_GENESIS_CLIQUE_POST_LONDON); internalTestSuccess( + this::runtimeConfiguration, miningParams -> { assertThat(miningParams.getPoaBlockTxsSelectionMaxTime()) .isEqualTo(PositiveNumber.fromInt(200)); @@ -412,16 +416,19 @@ protected MiningOptions optionsFromDomainObject(final MiningParameters domainObj @Override protected MiningOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { - final var miningOptions = besuCommand.getMiningOptions(); - miningOptions.setGenesisBlockPeriodSeconds( - besuCommand.getActualGenesisConfigOptions().isPoa() - ? OptionalInt.of(POA_BLOCK_PERIOD_SECONDS) - : OptionalInt.empty()); - return miningOptions; + return besuCommand.getMiningOptions(); } @Override protected String[] getNonOptionFields() { - return new String[] {"maybeGenesisBlockPeriodSeconds", "transactionSelectionService"}; + return new String[] {"transactionSelectionService"}; + } + + private MiningParameters runtimeConfiguration( + final TestBesuCommand besuCommand, final MiningParameters miningParameters) { + if (besuCommand.getActualGenesisConfigOptions().isPoa()) { + miningParameters.setBlockPeriodSeconds(POA_BLOCK_PERIOD_SECONDS); + } + return miningParameters; } } diff --git a/besu/src/test/java/org/hyperledger/besu/controller/AbstractBftBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/AbstractBftBesuControllerBuilderTest.java new file mode 100644 index 00000000000..bcfe8a2e181 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/controller/AbstractBftBesuControllerBuilderTest.java @@ -0,0 +1,204 @@ +/* + * Copyright Hyperledger Besu contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.controller; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; + +import org.hyperledger.besu.config.CheckpointConfigOptions; +import org.hyperledger.besu.config.GenesisConfigFile; +import org.hyperledger.besu.config.GenesisConfigOptions; +import org.hyperledger.besu.cryptoservices.NodeKey; +import org.hyperledger.besu.cryptoservices.NodeKeyUtils; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.GasLimitCalculator; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; +import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.MiningParameters; +import org.hyperledger.besu.ethereum.core.PrivacyParameters; +import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; +import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; +import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration; +import org.hyperledger.besu.ethereum.storage.StorageProvider; +import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; +import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; +import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; +import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.evm.log.LogsBloomFilter; +import org.hyperledger.besu.metrics.ObservableMetricsSystem; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; + +import java.math.BigInteger; +import java.nio.file.Path; +import java.time.Clock; +import java.util.List; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Range; +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public abstract class AbstractBftBesuControllerBuilderTest { + + protected BesuControllerBuilder bftBesuControllerBuilder; + @Mock protected GenesisConfigFile genesisConfigFile; + @Mock protected GenesisConfigOptions genesisConfigOptions; + @Mock private SynchronizerConfiguration synchronizerConfiguration; + @Mock private EthProtocolConfiguration ethProtocolConfiguration; + @Mock CheckpointConfigOptions checkpointConfigOptions; + @Mock private PrivacyParameters privacyParameters; + @Mock private Clock clock; + @Mock private StorageProvider storageProvider; + @Mock private GasLimitCalculator gasLimitCalculator; + @Mock private WorldStatePreimageStorage worldStatePreimageStorage; + private static final BigInteger networkId = BigInteger.ONE; + private static final NodeKey nodeKey = NodeKeyUtils.generate(); + private final TransactionPoolConfiguration poolConfiguration = + TransactionPoolConfiguration.DEFAULT; + private final ObservableMetricsSystem observableMetricsSystem = new NoOpMetricsSystem(); + protected final ObjectMapper objectMapper = new ObjectMapper(); + private final MiningParameters miningParameters = MiningParameters.newDefault(); + @TempDir Path tempDir; + + @BeforeEach + public void setup() throws JsonProcessingException { + // besu controller setup + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = + mock(ForestWorldStateKeyValueStorage.class); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); + + lenient().when(genesisConfigFile.getParentHash()).thenReturn(Hash.ZERO.toHexString()); + lenient().when(genesisConfigFile.getDifficulty()).thenReturn(Bytes.of(0).toHexString()); + lenient().when(genesisConfigFile.getMixHash()).thenReturn(Hash.ZERO.toHexString()); + lenient().when(genesisConfigFile.getNonce()).thenReturn(Long.toHexString(1)); + lenient().when(genesisConfigFile.getConfigOptions(any())).thenReturn(genesisConfigOptions); + lenient().when(genesisConfigFile.getConfigOptions()).thenReturn(genesisConfigOptions); + lenient().when(genesisConfigOptions.getCheckpointOptions()).thenReturn(checkpointConfigOptions); + lenient() + .when(storageProvider.createBlockchainStorage(any(), any())) + .thenReturn( + new KeyValueStoragePrefixedKeyBlockchainStorage( + new InMemoryKeyValueStorage(), + new VariablesKeyValueStorage(new InMemoryKeyValueStorage()), + new MainnetBlockHeaderFunctions())); + lenient() + .when( + storageProvider.createWorldStateStorageCoordinator( + DataStorageConfiguration.DEFAULT_FOREST_CONFIG)) + .thenReturn(worldStateStorageCoordinator); + lenient().when(worldStateKeyValueStorage.isWorldStateAvailable(any())).thenReturn(true); + lenient() + .when(worldStateKeyValueStorage.updater()) + .thenReturn(mock(ForestWorldStateKeyValueStorage.Updater.class)); + lenient() + .when(worldStatePreimageStorage.updater()) + .thenReturn(mock(WorldStatePreimageStorage.Updater.class)); + lenient() + .when(storageProvider.createWorldStatePreimageStorage()) + .thenReturn(worldStatePreimageStorage); + lenient().when(synchronizerConfiguration.getDownloaderParallelism()).thenReturn(1); + lenient().when(synchronizerConfiguration.getTransactionsParallelism()).thenReturn(1); + lenient().when(synchronizerConfiguration.getComputationParallelism()).thenReturn(1); + + lenient() + .when(synchronizerConfiguration.getBlockPropagationRange()) + .thenReturn(Range.closed(1L, 2L)); + + setupBftGenesisConfigOptions(); + + bftBesuControllerBuilder = + createBftControllerBuilder() + .genesisConfigFile(genesisConfigFile) + .synchronizerConfiguration(synchronizerConfiguration) + .ethProtocolConfiguration(ethProtocolConfiguration) + .networkId(networkId) + .miningParameters(miningParameters) + .metricsSystem(observableMetricsSystem) + .privacyParameters(privacyParameters) + .dataDirectory(tempDir) + .clock(clock) + .transactionPoolConfiguration(poolConfiguration) + .dataStorageConfiguration(DataStorageConfiguration.DEFAULT_FOREST_CONFIG) + .nodeKey(nodeKey) + .storageProvider(storageProvider) + .gasLimitCalculator(gasLimitCalculator) + .evmConfiguration(EvmConfiguration.DEFAULT) + .networkConfiguration(NetworkingConfiguration.create()); + } + + protected abstract void setupBftGenesisConfigOptions() throws JsonProcessingException; + + protected abstract BesuControllerBuilder createBftControllerBuilder(); + + @Test + public void miningParametersBlockPeriodSecondsIsUpdatedOnTransition() { + final var besuController = bftBesuControllerBuilder.build(); + final var protocolContext = besuController.getProtocolContext(); + + final BlockHeader header1 = + new BlockHeader( + protocolContext.getBlockchain().getChainHeadHash(), + Hash.EMPTY_TRIE_HASH, + Address.ZERO, + Hash.EMPTY_TRIE_HASH, + Hash.EMPTY_TRIE_HASH, + Hash.EMPTY_TRIE_HASH, + LogsBloomFilter.builder().build(), + Difficulty.ONE, + 1, + 0, + 0, + 0, + protocolContext.getBlockchain().getChainHead().getBlockHeader().getExtraData(), + Wei.ZERO, + Hash.EMPTY, + 0, + null, + null, + null, + null, + null, + getBlockHeaderFunctions()); + final Block block1 = new Block(header1, BlockBody.empty()); + + protocolContext.getBlockchain().appendBlock(block1, List.of()); + + assertThat(miningParameters.getBlockPeriodSeconds()).isNotEmpty().hasValue(2); + assertThat(miningParameters.getBlockTxsSelectionMaxTime()).isEqualTo(2000 * 75 / 100); + } + + protected abstract BlockHeaderFunctions getBlockHeaderFunctions(); +} diff --git a/besu/src/test/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilderTest.java new file mode 100644 index 00000000000..b96a052c61a --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilderTest.java @@ -0,0 +1,231 @@ +/* + * Copyright Hyperledger Besu contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.controller; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.config.CheckpointConfigOptions; +import org.hyperledger.besu.config.GenesisConfigFile; +import org.hyperledger.besu.config.GenesisConfigOptions; +import org.hyperledger.besu.config.ImmutableCliqueConfigOptions; +import org.hyperledger.besu.config.TransitionsConfigOptions; +import org.hyperledger.besu.consensus.clique.CliqueBlockHeaderFunctions; +import org.hyperledger.besu.cryptoservices.NodeKey; +import org.hyperledger.besu.cryptoservices.NodeKeyUtils; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.GasLimitCalculator; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.MiningParameters; +import org.hyperledger.besu.ethereum.core.PrivacyParameters; +import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; +import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; +import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; +import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration; +import org.hyperledger.besu.ethereum.storage.StorageProvider; +import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; +import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; +import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; +import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.evm.log.LogsBloomFilter; +import org.hyperledger.besu.metrics.ObservableMetricsSystem; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; + +import java.math.BigInteger; +import java.nio.file.Path; +import java.time.Clock; +import java.util.List; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.Range; +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class CliqueBesuControllerBuilderTest { + + private BesuControllerBuilder cliqueBesuControllerBuilder; + + @Mock private GenesisConfigFile genesisConfigFile; + @Mock private GenesisConfigOptions genesisConfigOptions; + @Mock private SynchronizerConfiguration synchronizerConfiguration; + @Mock private EthProtocolConfiguration ethProtocolConfiguration; + @Mock private CheckpointConfigOptions checkpointConfigOptions; + @Mock private PrivacyParameters privacyParameters; + @Mock private Clock clock; + @Mock private StorageProvider storageProvider; + @Mock private GasLimitCalculator gasLimitCalculator; + @Mock private WorldStatePreimageStorage worldStatePreimageStorage; + private static final BigInteger networkId = BigInteger.ONE; + private static final NodeKey nodeKey = NodeKeyUtils.generate(); + private final TransactionPoolConfiguration poolConfiguration = + TransactionPoolConfiguration.DEFAULT; + private final ObservableMetricsSystem observableMetricsSystem = new NoOpMetricsSystem(); + private final ObjectMapper objectMapper = new ObjectMapper(); + private final MiningParameters miningParameters = MiningParameters.newDefault(); + + @TempDir Path tempDir; + + @BeforeEach + public void setup() throws JsonProcessingException { + // Clique Besu controller setup + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = + mock(ForestWorldStateKeyValueStorage.class); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); + + lenient().when(genesisConfigFile.getParentHash()).thenReturn(Hash.ZERO.toHexString()); + lenient().when(genesisConfigFile.getDifficulty()).thenReturn(Bytes.of(0).toHexString()); + when(genesisConfigFile.getExtraData()) + .thenReturn( + "0x0000000000000000000000000000000000000000000000000000000000000000b9b81ee349c3807e46bc71aa2632203c5b4620340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + lenient().when(genesisConfigFile.getMixHash()).thenReturn(Hash.ZERO.toHexString()); + lenient().when(genesisConfigFile.getNonce()).thenReturn(Long.toHexString(1)); + lenient().when(genesisConfigFile.getConfigOptions(any())).thenReturn(genesisConfigOptions); + lenient().when(genesisConfigFile.getConfigOptions()).thenReturn(genesisConfigOptions); + lenient().when(genesisConfigOptions.getCheckpointOptions()).thenReturn(checkpointConfigOptions); + lenient() + .when(storageProvider.createBlockchainStorage(any(), any())) + .thenReturn( + new KeyValueStoragePrefixedKeyBlockchainStorage( + new InMemoryKeyValueStorage(), + new VariablesKeyValueStorage(new InMemoryKeyValueStorage()), + new MainnetBlockHeaderFunctions())); + lenient() + .when( + storageProvider.createWorldStateStorageCoordinator( + DataStorageConfiguration.DEFAULT_FOREST_CONFIG)) + .thenReturn(worldStateStorageCoordinator); + lenient().when(worldStateKeyValueStorage.isWorldStateAvailable(any())).thenReturn(true); + lenient() + .when(worldStateKeyValueStorage.updater()) + .thenReturn(mock(ForestWorldStateKeyValueStorage.Updater.class)); + lenient() + .when(worldStatePreimageStorage.updater()) + .thenReturn(mock(WorldStatePreimageStorage.Updater.class)); + lenient() + .when(storageProvider.createWorldStatePreimageStorage()) + .thenReturn(worldStatePreimageStorage); + lenient().when(synchronizerConfiguration.getDownloaderParallelism()).thenReturn(1); + lenient().when(synchronizerConfiguration.getTransactionsParallelism()).thenReturn(1); + lenient().when(synchronizerConfiguration.getComputationParallelism()).thenReturn(1); + + lenient() + .when(synchronizerConfiguration.getBlockPropagationRange()) + .thenReturn(Range.closed(1L, 2L)); + + // clique prepForBuild setup + lenient() + .when(genesisConfigOptions.getCliqueConfigOptions()) + .thenReturn( + ImmutableCliqueConfigOptions.builder() + .epochLength(30) + .createEmptyBlocks(true) + .blockPeriodSeconds(1) + .build()); + + final var jsonTransitions = + (ObjectNode) + objectMapper.readTree( + """ + {"clique": [ + { + "block": 2, + "blockperiodseconds": 2 + } + ]} + """); + + lenient() + .when(genesisConfigOptions.getTransitions()) + .thenReturn(new TransitionsConfigOptions(jsonTransitions)); + + cliqueBesuControllerBuilder = + new CliqueBesuControllerBuilder() + .genesisConfigFile(genesisConfigFile) + .synchronizerConfiguration(synchronizerConfiguration) + .ethProtocolConfiguration(ethProtocolConfiguration) + .networkId(networkId) + .miningParameters(miningParameters) + .metricsSystem(observableMetricsSystem) + .privacyParameters(privacyParameters) + .dataDirectory(tempDir) + .clock(clock) + .transactionPoolConfiguration(poolConfiguration) + .dataStorageConfiguration(DataStorageConfiguration.DEFAULT_FOREST_CONFIG) + .nodeKey(nodeKey) + .storageProvider(storageProvider) + .gasLimitCalculator(gasLimitCalculator) + .evmConfiguration(EvmConfiguration.DEFAULT) + .networkConfiguration(NetworkingConfiguration.create()); + } + + @Test + public void miningParametersBlockPeriodSecondsIsUpdatedOnTransition() { + final var besuController = cliqueBesuControllerBuilder.build(); + final var protocolContext = besuController.getProtocolContext(); + + final BlockHeader header1 = + new BlockHeader( + protocolContext.getBlockchain().getChainHeadHash(), + Hash.EMPTY_TRIE_HASH, + Address.ZERO, + Hash.EMPTY_TRIE_HASH, + Hash.EMPTY_TRIE_HASH, + Hash.EMPTY_TRIE_HASH, + LogsBloomFilter.builder().build(), + Difficulty.ONE, + 1, + 0, + 0, + 0, + Bytes.EMPTY, + Wei.ZERO, + Hash.EMPTY, + 0, + null, + null, + null, + null, + null, + new CliqueBlockHeaderFunctions()); + final Block block1 = new Block(header1, BlockBody.empty()); + + protocolContext.getBlockchain().appendBlock(block1, List.of()); + + assertThat(miningParameters.getBlockPeriodSeconds()).isNotEmpty().hasValue(2); + assertThat(miningParameters.getBlockTxsSelectionMaxTime()).isEqualTo(2000 * 75 / 100); + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/controller/IbftBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/IbftBesuControllerBuilderTest.java new file mode 100644 index 00000000000..a819a140311 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/controller/IbftBesuControllerBuilderTest.java @@ -0,0 +1,73 @@ +/* + * Copyright Hyperledger Besu contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.controller; + +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.config.JsonBftConfigOptions; +import org.hyperledger.besu.config.TransitionsConfigOptions; +import org.hyperledger.besu.consensus.common.bft.BftBlockHeaderFunctions; +import org.hyperledger.besu.consensus.common.bft.MutableBftConfigOptions; +import org.hyperledger.besu.consensus.ibft.IbftExtraDataCodec; +import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class IbftBesuControllerBuilderTest extends AbstractBftBesuControllerBuilderTest { + + @Override + public void setupBftGenesisConfigOptions() throws JsonProcessingException { + + // Ibft prepForBuild setup + lenient() + .when(genesisConfigOptions.getBftConfigOptions()) + .thenReturn(new MutableBftConfigOptions(JsonBftConfigOptions.DEFAULT)); + + final var jsonTransitions = + (ObjectNode) + objectMapper.readTree( + """ + {"ibft2": [ + { + "block": 2, + "blockperiodseconds": 2 + } + ]} + """); + + lenient() + .when(genesisConfigOptions.getTransitions()) + .thenReturn(new TransitionsConfigOptions(jsonTransitions)); + + when(genesisConfigFile.getExtraData()) + .thenReturn( + "0xf83ea00000000000000000000000000000000000000000000000000000000000000000d594c2ab482b506de561668e07f04547232a72897daf808400000000c0"); + } + + @Override + protected BesuControllerBuilder createBftControllerBuilder() { + return new IbftBesuControllerBuilder(); + } + + @Override + protected BlockHeaderFunctions getBlockHeaderFunctions() { + return BftBlockHeaderFunctions.forOnchainBlock(new IbftExtraDataCodec()); + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java index e768c49e567..e3e99285b66 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java @@ -16,167 +16,77 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import org.hyperledger.besu.config.CheckpointConfigOptions; -import org.hyperledger.besu.config.GenesisConfigFile; -import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.config.JsonQbftConfigOptions; import org.hyperledger.besu.config.TransitionsConfigOptions; +import org.hyperledger.besu.consensus.common.bft.BftBlockHeaderFunctions; import org.hyperledger.besu.consensus.common.bft.BftContext; import org.hyperledger.besu.consensus.common.validator.ValidatorProvider; import org.hyperledger.besu.consensus.qbft.MutableQbftConfigOptions; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.validator.ForkingValidatorProvider; -import org.hyperledger.besu.cryptoservices.NodeKey; -import org.hyperledger.besu.cryptoservices.NodeKeyUtils; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; -import org.hyperledger.besu.ethereum.core.MiningParameters; -import org.hyperledger.besu.ethereum.core.PrivacyParameters; -import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; -import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; -import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; -import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; -import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration; -import org.hyperledger.besu.ethereum.storage.StorageProvider; -import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; -import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage; -import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; -import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; -import org.hyperledger.besu.evm.internal.EvmConfiguration; -import org.hyperledger.besu.metrics.ObservableMetricsSystem; -import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; - -import java.math.BigInteger; -import java.nio.file.Path; -import java.time.Clock; +import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; + import java.util.List; -import com.google.common.collect.Range; -import org.apache.tuweni.bytes.Bytes; -import org.junit.jupiter.api.BeforeEach; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.ObjectNode; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.io.TempDir; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -public class QbftBesuControllerBuilderTest { - - private BesuControllerBuilder qbftBesuControllerBuilder; - - @Mock private GenesisConfigFile genesisConfigFile; - @Mock private GenesisConfigOptions genesisConfigOptions; - @Mock private SynchronizerConfiguration synchronizerConfiguration; - @Mock private EthProtocolConfiguration ethProtocolConfiguration; - @Mock CheckpointConfigOptions checkpointConfigOptions; - @Mock private MiningParameters miningParameters; - @Mock private PrivacyParameters privacyParameters; - @Mock private Clock clock; - @Mock private StorageProvider storageProvider; - @Mock private GasLimitCalculator gasLimitCalculator; - @Mock private WorldStatePreimageStorage worldStatePreimageStorage; - private static final BigInteger networkId = BigInteger.ONE; - private static final NodeKey nodeKey = NodeKeyUtils.generate(); - private final TransactionPoolConfiguration poolConfiguration = - TransactionPoolConfiguration.DEFAULT; - private final ObservableMetricsSystem observableMetricsSystem = new NoOpMetricsSystem(); - - @TempDir Path tempDir; - - @BeforeEach - public void setup() { - // besu controller setup - final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = - mock(ForestWorldStateKeyValueStorage.class); - final WorldStateStorageCoordinator worldStateStorageCoordinator = - new WorldStateStorageCoordinator(worldStateKeyValueStorage); - - lenient().when(genesisConfigFile.getParentHash()).thenReturn(Hash.ZERO.toHexString()); - lenient().when(genesisConfigFile.getDifficulty()).thenReturn(Bytes.of(0).toHexString()); - when(genesisConfigFile.getExtraData()).thenReturn(Bytes.EMPTY.toHexString()); - lenient().when(genesisConfigFile.getMixHash()).thenReturn(Hash.ZERO.toHexString()); - lenient().when(genesisConfigFile.getNonce()).thenReturn(Long.toHexString(1)); - lenient().when(genesisConfigFile.getConfigOptions(any())).thenReturn(genesisConfigOptions); - lenient().when(genesisConfigFile.getConfigOptions()).thenReturn(genesisConfigOptions); - lenient().when(genesisConfigOptions.getCheckpointOptions()).thenReturn(checkpointConfigOptions); - lenient() - .when(storageProvider.createBlockchainStorage(any(), any())) - .thenReturn( - new KeyValueStoragePrefixedKeyBlockchainStorage( - new InMemoryKeyValueStorage(), - new VariablesKeyValueStorage(new InMemoryKeyValueStorage()), - new MainnetBlockHeaderFunctions())); +public class QbftBesuControllerBuilderTest extends AbstractBftBesuControllerBuilderTest { - lenient() - .when( - storageProvider.createWorldStateStorageCoordinator( - DataStorageConfiguration.DEFAULT_FOREST_CONFIG)) - .thenReturn(worldStateStorageCoordinator); - lenient().when(worldStateKeyValueStorage.isWorldStateAvailable(any())).thenReturn(true); - lenient() - .when(worldStateKeyValueStorage.updater()) - .thenReturn(mock(ForestWorldStateKeyValueStorage.Updater.class)); - lenient() - .when(worldStatePreimageStorage.updater()) - .thenReturn(mock(WorldStatePreimageStorage.Updater.class)); - lenient() - .when(storageProvider.createWorldStatePreimageStorage()) - .thenReturn(worldStatePreimageStorage); - lenient().when(synchronizerConfiguration.getDownloaderParallelism()).thenReturn(1); - lenient().when(synchronizerConfiguration.getTransactionsParallelism()).thenReturn(1); - lenient().when(synchronizerConfiguration.getComputationParallelism()).thenReturn(1); - - lenient() - .when(synchronizerConfiguration.getBlockPropagationRange()) - .thenReturn(Range.closed(1L, 2L)); + @Override + public void setupBftGenesisConfigOptions() throws JsonProcessingException { // qbft prepForBuild setup lenient() .when(genesisConfigOptions.getQbftConfigOptions()) .thenReturn(new MutableQbftConfigOptions(JsonQbftConfigOptions.DEFAULT)); + + final var jsonTransitions = + (ObjectNode) + objectMapper.readTree( + """ + {"qbft": [ + { + "block": 2, + "blockperiodseconds": 2 + } + ]} + """); + lenient() .when(genesisConfigOptions.getTransitions()) - .thenReturn(mock(TransitionsConfigOptions.class)); + .thenReturn(new TransitionsConfigOptions(jsonTransitions)); + lenient() .when(genesisConfigFile.getExtraData()) .thenReturn( QbftExtraDataCodec.createGenesisExtraDataString(List.of(Address.fromHexString("1")))); + } + + @Override + protected BesuControllerBuilder createBftControllerBuilder() { + return new QbftBesuControllerBuilder(); + } - qbftBesuControllerBuilder = - new QbftBesuControllerBuilder() - .genesisConfigFile(genesisConfigFile) - .synchronizerConfiguration(synchronizerConfiguration) - .ethProtocolConfiguration(ethProtocolConfiguration) - .networkId(networkId) - .miningParameters(miningParameters) - .metricsSystem(observableMetricsSystem) - .privacyParameters(privacyParameters) - .dataDirectory(tempDir) - .clock(clock) - .transactionPoolConfiguration(poolConfiguration) - .dataStorageConfiguration(DataStorageConfiguration.DEFAULT_FOREST_CONFIG) - .nodeKey(nodeKey) - .storageProvider(storageProvider) - .gasLimitCalculator(gasLimitCalculator) - .evmConfiguration(EvmConfiguration.DEFAULT) - .networkConfiguration(NetworkingConfiguration.create()); + @Override + protected BlockHeaderFunctions getBlockHeaderFunctions() { + return BftBlockHeaderFunctions.forOnchainBlock(new QbftExtraDataCodec()); } @Test public void forkingValidatorProviderIsAvailableOnBftContext() { - final BesuController besuController = qbftBesuControllerBuilder.build(); + final BesuController besuController = bftBesuControllerBuilder.build(); final ValidatorProvider validatorProvider = besuController @@ -192,7 +102,7 @@ public void missingTransactionValidatorProviderThrowsError() { when(protocolContext.getBlockchain()).thenReturn(mock(MutableBlockchain.class)); assertThatThrownBy( - () -> qbftBesuControllerBuilder.createAdditionalJsonRpcMethodFactory(protocolContext)) + () -> bftBesuControllerBuilder.createAdditionalJsonRpcMethodFactory(protocolContext)) .isInstanceOf(NullPointerException.class) .hasMessage("transactionValidatorProvider should have been initialised"); } diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockSchedulerTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockSchedulerTest.java index 8421ac3f195..fddcce39091 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockSchedulerTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockSchedulerTest.java @@ -42,7 +42,6 @@ import org.junit.jupiter.api.Test; public class CliqueBlockSchedulerTest { - private final KeyPair proposerKeyPair = SignatureAlgorithmFactory.getInstance().generateKeyPair(); private Address localAddr; diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java index ebca2bb17aa..4c843b2eaea 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java @@ -1405,9 +1405,9 @@ protected MiningParameters createMiningParameters( MutableInitValues.builder() .minTransactionGasPrice(minGasPrice) .minBlockOccupancyRatio(minBlockOccupancyRatio) + .blockPeriodSeconds(genesisBlockPeriodSeconds) .build()) .transactionSelectionService(transactionSelectionService) - .genesisBlockPeriodSeconds(genesisBlockPeriodSeconds) .poaBlockTxsSelectionMaxTime(minBlockTimePercentage) .build(); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java index 0a7144d30d9..febce15fe13 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java @@ -122,6 +122,15 @@ public MiningParameters setNonceGenerator(final Iterable nonceGenerator) { return this; } + public OptionalInt getBlockPeriodSeconds() { + return getMutableRuntimeValues().blockPeriodSeconds; + } + + public MiningParameters setBlockPeriodSeconds(final int blockPeriodSeconds) { + getMutableRuntimeValues().blockPeriodSeconds = OptionalInt.of(blockPeriodSeconds); + return this; + } + @Value.Default public boolean isStratumMiningEnabled() { return false; @@ -161,12 +170,10 @@ public void registerPluginTransactionSelectorFactory( }; } - public abstract OptionalInt getGenesisBlockPeriodSeconds(); - - @Value.Derived public long getBlockTxsSelectionMaxTime() { - if (getGenesisBlockPeriodSeconds().isPresent()) { - return (TimeUnit.SECONDS.toMillis(getGenesisBlockPeriodSeconds().getAsInt()) + final var maybeBlockPeriodSeconds = getMutableRuntimeValues().blockPeriodSeconds; + if (maybeBlockPeriodSeconds.isPresent()) { + return (TimeUnit.SECONDS.toMillis(maybeBlockPeriodSeconds.getAsInt()) * getPoaBlockTxsSelectionMaxTime().getValue()) / 100; } @@ -222,6 +229,8 @@ default double getMinBlockOccupancyRatio() { return DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO; } + OptionalInt getBlockPeriodSeconds(); + Optional
getCoinbase(); OptionalLong getTargetGasLimit(); @@ -238,6 +247,7 @@ static class MutableRuntimeValues { private volatile Optional
coinbase; private volatile OptionalLong targetGasLimit; private volatile Optional> nonceGenerator; + private volatile OptionalInt blockPeriodSeconds; private MutableRuntimeValues(final MutableInitValues initValues) { miningEnabled = initValues.isMiningEnabled(); @@ -248,6 +258,7 @@ private MutableRuntimeValues(final MutableInitValues initValues) { coinbase = initValues.getCoinbase(); targetGasLimit = initValues.getTargetGasLimit(); nonceGenerator = initValues.nonceGenerator(); + blockPeriodSeconds = initValues.getBlockPeriodSeconds(); } @Override @@ -262,7 +273,8 @@ public boolean equals(final Object o) { && Objects.equals(coinbase, that.coinbase) && Objects.equals(minPriorityFeePerGas, that.minPriorityFeePerGas) && Objects.equals(targetGasLimit, that.targetGasLimit) - && Objects.equals(nonceGenerator, that.nonceGenerator); + && Objects.equals(nonceGenerator, that.nonceGenerator) + && Objects.equals(blockPeriodSeconds, that.blockPeriodSeconds); } @Override @@ -275,7 +287,8 @@ public int hashCode() { minBlockOccupancyRatio, coinbase, targetGasLimit, - nonceGenerator); + nonceGenerator, + blockPeriodSeconds); } @Override @@ -297,6 +310,8 @@ public String toString() { + targetGasLimit + ", nonceGenerator=" + nonceGenerator + + ", blockPeriodSeconds=" + + blockPeriodSeconds + '}'; } } From 8dba298108d56d09886626610adf311b262f2190 Mon Sep 17 00:00:00 2001 From: Matt Whitehead Date: Tue, 12 Mar 2024 10:26:33 +0000 Subject: [PATCH 06/11] Don't start the BFT mining coordinator when it is created, just enable it (#6675) * Don't start a BFT mining coordinator when it is created, just enable it Signed-off-by: Matthew Whitehead * Update change log Signed-off-by: Matthew Whitehead --------- Signed-off-by: Matthew Whitehead Signed-off-by: Matt Whitehead --- CHANGELOG.md | 1 + .../besu/controller/IbftBesuControllerBuilder.java | 4 ---- .../besu/controller/QbftBesuControllerBuilder.java | 4 ---- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ceaa5b1b50..ee32ad05f85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ ### Bug fixes - Make block transaction selection max time aware of PoA transitions [#6676](https://github.com/hyperledger/besu/pull/6676) +- Don't enable the BFT mining coordinator when running sub commands such as `blocks export` [#6675](https://github.com/hyperledger/besu/pull/6675) ### Download Links diff --git a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java index eb261ff42ba..c4a412e4dc8 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java @@ -246,11 +246,7 @@ protected MiningCoordinator createMiningCoordinator( .getBlockPeriodSeconds())); if (syncState.isInitialSyncPhaseDone()) { - LOG.info("Starting IBFT mining coordinator"); ibftMiningCoordinator.enable(); - ibftMiningCoordinator.start(); - } else { - LOG.info("IBFT mining coordinator not starting while initial sync in progress"); } syncState.subscribeCompletionReached( diff --git a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java index b26088e73f1..a622001ef89 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java @@ -286,11 +286,7 @@ protected MiningCoordinator createMiningCoordinator( .getBlockPeriodSeconds())); if (syncState.isInitialSyncPhaseDone()) { - LOG.info("Starting QBFT mining coordinator"); miningCoordinator.enable(); - miningCoordinator.start(); - } else { - LOG.info("QBFT mining coordinator not starting while initial sync in progress"); } syncState.subscribeCompletionReached( From 934e43558bd4f6ed546e076d27990b5d032426f5 Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Tue, 12 Mar 2024 18:24:22 -0400 Subject: [PATCH 07/11] Gha updates (#6705) * make artifacts more snapshot friendly * break out new workflows for snapshots, and a develop releease * removes checking for approval, runs on pr update * adds concurrency so updated refs cancel prior runs if still running * explicitly disable caching on gradle setup tasks --------- Signed-off-by: Justin Florentine --- .github/workflows/acceptance-tests.yml | 47 ++------- .github/workflows/artifacts.yml | 46 ++++++--- .github/workflows/codeql.yml | 16 ++- .github/workflows/develop.yml | 64 ++++++++++++ .github/workflows/docker.yml | 7 ++ .github/workflows/integration-tests.yml | 52 ++-------- .github/workflows/nightly.yml | 125 ------------------------ .github/workflows/pre-review.yml | 20 +++- .github/workflows/reference-tests.yml | 57 ++--------- .github/workflows/release.yml | 3 +- .github/workflows/sonarcloud.yml | 2 + 11 files changed, 154 insertions(+), 285 deletions(-) create mode 100644 .github/workflows/develop.yml delete mode 100644 .github/workflows/nightly.yml diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 39af80ba6e6..bd89270942e 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -5,58 +5,22 @@ on: branches: - main - release-* - pull_request_review: - types: [submitted] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true env: GRADLE_OPTS: "-Xmx6g -Dorg.gradle.daemon=false" total-runners: 16 jobs: - shouldRun: - name: checks to ensure we should run - # necessary because there is no single PR approved event, need to check all comments/approvals/denials - runs-on: ubuntu-22.04 - outputs: - shouldRun: ${{steps.shouldRun.outputs.result}} - steps: - - name: required check - id: shouldRun - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea - env: - # fun fact, this changes based on incoming event, it will be different when we run this on pushes to main - RELEVANT_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - with: - script: | - const { RELEVANT_SHA } = process.env; - const { data: { statuses } } = await github.rest.repos.getCombinedStatusForRef({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: RELEVANT_SHA, - }); - const acceptanceTested = statuses && statuses.filter(({ context }) => context === 'accepttests-passed'); - const alreadyRun = acceptanceTested && acceptanceTested.find(({ state }) => state === 'success') > 0; - const { data: reviews } = await github.rest.pulls.listReviews({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.issue.number, - }); - const approvingReviews = reviews && reviews.filter(review => review.state === 'APPROVED'); - const shouldRun = !alreadyRun && github.actor != 'dependabot[bot]' && (approvingReviews.length > 0); - - console.log("tests should be run = %j", shouldRun); - console.log("alreadyRun = %j", alreadyRun); - console.log("approvingReviews = %j", approvingReviews.length); - - return shouldRun; acceptanceTestEthereum: runs-on: ubuntu-22.04 name: "Acceptance Runner" - needs: shouldRun permissions: statuses: write checks: write - if: ${{ needs.shouldRun.outputs.shouldRun == 'true'}} strategy: fail-fast: true matrix: @@ -81,6 +45,8 @@ jobs: if_no_artifact_found: true - name: setup gradle uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 + with: + cache-disabled: true - name: Split tests id: split-tests uses: r7kamura/split-tests-by-timings@9322bd292d9423e2bc5a65bec548901801341e3f @@ -111,6 +77,7 @@ jobs: report_paths: 'acceptance-tests/tests/build/test-results/**/TEST-*.xml' annotate_only: true accepttests-passed: + name: "accepttests-passed" runs-on: ubuntu-22.04 needs: [ acceptanceTestEthereum ] permissions: diff --git a/.github/workflows/artifacts.yml b/.github/workflows/artifacts.yml index 6923a43a94e..6a737252bcc 100644 --- a/.github/workflows/artifacts.yml +++ b/.github/workflows/artifacts.yml @@ -1,11 +1,12 @@ -name: artifacts +name: release artifacts on: - workflow_dispatch: release: types: - prereleased +env: + GRADLE_OPTS: "-Dorg.gradle.parallel=true -Dorg.gradle.caching=true" jobs: artifacts: @@ -22,9 +23,11 @@ jobs: java-version: '17' - name: setup gradle uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 - - name: assemble distributions + with: + cache-disabled: true + - name: assemble release run: - ./gradlew -Prelease.releaseVersion=${{github.ref_name}} -Pversion=${{github.ref_name}} assemble -Dorg.gradle.parallel=true -Dorg.gradle.caching=true + ./gradlew -Prelease.releaseVersion=${{github.ref_name}} -Pversion=${{github.ref_name}} assemble - name: hashes id: hashes run: | @@ -43,16 +46,6 @@ jobs: path: 'build/distributions/besu*.zip' name: besu-${{ github.ref_name }}.zip compression-level: 0 - - name: Upload Release assets - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 - with: - append_body: true - files: | - build/distributions/besu*.tar.gz - build/distributions/besu*.zip - body: | - ${{steps.hashes.outputs.tarSha}} - ${{steps.hashes.outputs.zipSha}} testWindows: runs-on: windows-2022 needs: artifacts @@ -67,13 +60,34 @@ jobs: - name: Download zip uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe with: - name: besu-${{ github.ref_name }}.zip + pattern: besu-*.zip + merge-multiple: true - name: test Besu run: | + dir unzip besu-*.zip -d besu-tmp cd besu-tmp mv besu-* ../besu cd .. besu\bin\besu.bat --help besu\bin\besu.bat --version - + publish: + runs-on: ubuntu-22.04 + needs: testWindows + steps: + - name: Download archives + uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe + with: + pattern: besu-* + merge-multiple: true + path: 'build/distributions' + - name: Upload Release assets + uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 + with: + append_body: true + files: | + build/distributions/besu*.tar.gz + build/distributions/besu*.zip + body: | + ${{steps.hashes.outputs.tarSha}} + ${{steps.hashes.outputs.zipSha}} \ No newline at end of file diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f0340e168c7..0a50ec57c2d 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,15 +13,11 @@ name: "CodeQL" on: workflow_dispatch: - push: - branches: [ main ] - pull_request: - branches: [ main ] - paths-ignore: - - '**/*.json' - - '**/*.md' - - '**/*.properties' - - '**/*.txt' + schedule: + # * is a special character in YAML so you have to quote this string + # expression evaluates to midnight every night + - cron: '0 0 * * *' + jobs: analyze: name: Analyze @@ -50,6 +46,8 @@ jobs: - name: setup gradle uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 + with: + cache-disabled: true - name: compileJava noscan run: | JAVA_OPTS="-Xmx2048M" ./gradlew --no-scan compileJava diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml new file mode 100644 index 00000000000..fbafc9e4f23 --- /dev/null +++ b/.github/workflows/develop.yml @@ -0,0 +1,64 @@ + +name: develop pre-release + +on: + push: + branches: + - main +env: + GRADLE_OPTS: "-Dorg.gradle.parallel=true -Dorg.gradle.caching=true" + +jobs: + artifacts: + runs-on: ubuntu-22.04 + permissions: + contents: write + steps: + - name: checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - name: Set up JDK 17 + uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 + with: + distribution: 'temurin' + java-version: '17' + - name: setup gradle + uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 + with: + cache-disabled: true + - name: assemble release + run: + ./gradlew assemble + - name: upload tarball + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + with: + path: 'build/distributions/besu*.tar.gz' + name: besu-develop.tar.gz + compression-level: 0 + - name: hashes + id: hashes + run: | + cd build/distributions + echo "zipSha=$(shasum -a 256 besu*.zip)" >> $GITHUB_OUTPUT + echo "tarSha=$(shasum -a 256 besu*.tar.gz)" >> $GITHUB_OUTPUT + - name: upload zipfile + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + with: + path: 'build/distributions/besu*.zip' + name: besu-develop.zip + compression-level: 0 + - name: Upload Release assets + uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 + with: + prerelease: true + name: develop + tag_name: develop + fail_on_unmatched_files: true + append_body: false + files: | + build/distributions/besu*.tar.gz + build/distributions/besu*.zip + body: | + This is an automated, bleeding edge build from the tip of ${{ github.ref_name }}. No promises. YOLO. + + ${{steps.hashes.outputs.tarSha}} + ${{steps.hashes.outputs.zipSha}} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8889b0dc7ad..3155667b9e6 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -19,6 +19,8 @@ jobs: java-version: 17 - name: setup gradle uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 + with: + cache-disabled: true - name: hadoLint_openj9-jdk_17 run: docker run --rm -i hadolint/hadolint < docker/openj9-jdk-17/Dockerfile - name: hadoLint_openjdk_17 @@ -66,6 +68,8 @@ jobs: java-version: 17 - name: setup gradle uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 + with: + cache-disabled: true - name: install goss run: | mkdir -p docker/reports @@ -81,6 +85,7 @@ jobs: env: architecture: ${{ steps.prep.outputs.ARCH }} with: + cache-disabled: true arguments: testDocker -PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }} -Pversion=${{github.ref_name}} -Prelease.releaseVersion=${{ github.ref_name }} - name: publish env: @@ -102,6 +107,8 @@ jobs: java-version: 17 - name: setup gradle uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 + with: + cache-disabled: true - name: login to ${{ env.registry }} uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d with: diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 80a2eca1e27..944422cbdf8 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -5,54 +5,18 @@ on: branches: - main - release-* - pull_request_review: - types: - - submitted + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true env: - GRADLE_OPTS: "-Xmx6g -Dorg.gradle.daemon=false" + GRADLE_OPTS: "-Xmx6g -Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.caching=true" jobs: - shouldRun: - name: checks to ensure we should run - runs-on: ubuntu-22.04 - outputs: - shouldRun: ${{steps.shouldRun.outputs.result}} - steps: - - name: required check - id: shouldRun - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea - env: - # fun fact, this changes based on incoming event, it will be different when we run this on pushes to main - RELEVANT_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - with: - script: | - const { RELEVANT_SHA } = process.env; - const { data: { statuses } } = await github.rest.repos.getCombinedStatusForRef({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: RELEVANT_SHA, - }); - - const intTested = statuses && statuses.filter(({ context }) => context === 'integration-tests'); - const alreadyRun = intTested && intTested.find(({ state }) => state === 'success') > 0; - const { data: reviews } = await github.rest.pulls.listReviews({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.issue.number, - }); - const approvingReviews = reviews && reviews.filter(review => review.state === 'APPROVED'); - const shouldRun = !alreadyRun && github.actor != 'dependabot[bot]' && (approvingReviews.length > 0); - - console.log("tests should be run = %j", shouldRun); - console.log("alreadyRun = %j", alreadyRun); - console.log("approvingReviews = %j", approvingReviews.length); - - return shouldRun; integration-tests: + name: "integration-passed" runs-on: ubuntu-22.04 - needs: shouldRun - if: ${{ needs.shouldRun.outputs.shouldRun == 'true' }} permissions: statuses: write checks: write @@ -68,8 +32,10 @@ jobs: java-version: 17 - name: setup gradle uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 + with: + cache-disabled: true - name: run integration tests - run: ./gradlew integrationTest compileJmh -Dorg.gradle.parallel=true -Dorg.gradle.caching=true + run: ./gradlew integrationTest compileJmh - name: Publish Test Report uses: mikepenz/action-junit-report@5f47764eec0e1c1f19f40c8e60a5ba47e47015c5 if: (success() || failure()) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml deleted file mode 100644 index 3defa71ab5a..00000000000 --- a/.github/workflows/nightly.yml +++ /dev/null @@ -1,125 +0,0 @@ -name: nightly - -on: - workflow_dispatch: - schedule: - # * is a special character in YAML so you have to quote this string - # expression evaluates to midnight every night - - cron: '0 0 * * *' - -env: - nightly-tag: develop - registry: docker.io - -jobs: - hadolint: - runs-on: ubuntu-22.04 - steps: - - name: Checkout Repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - - name: Set up Java - uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 - with: - distribution: temurin - java-version: 17 - - name: setup gradle - uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 - - name: hadoLint_openj9-jdk_17 - run: docker run --rm -i hadolint/hadolint < docker/openj9-jdk-17/Dockerfile - - name: hadoLint_openjdk_17 - run: docker run --rm -i hadolint/hadolint < docker/openjdk-17/Dockerfile - - name: hadoLint_openjdk_17_debug - run: docker run --rm -i hadolint/hadolint < docker/openjdk-17-debug/Dockerfile - - name: hadoLint_openjdk_latest - run: docker run --rm -i hadolint/hadolint < docker/openjdk-latest/Dockerfile - - name: hadoLint_graalvm - run: docker run --rm -i hadolint/hadolint < docker/graalvm/Dockerfile - buildDocker: - needs: hadolint - permissions: - contents: read - packages: write - strategy: - fail-fast: false - matrix: - platform: - - ubuntu-22.04 - - [self-hosted, ARM64] - runs-on: ${{ matrix.platform }} - steps: - - name: Prepare - id: prep - run: | - platform=${{ matrix.platform }} - if [ "$platform" = 'ubuntu-22.04' ]; then - echo "PLATFORM_PAIR=linux-amd64" >> $GITHUB_OUTPUT - echo "ARCH=amd64" >> $GITHUB_OUTPUT - else - echo "PLATFORM_PAIR=linux-arm64" >> $GITHUB_OUTPUT - echo "ARCH=arm64" >> $GITHUB_OUTPUT - fi - - name: Checkout Repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - - name: short sha - id: shortSha - run: echo "sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - - name: Set up Java - uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 - with: - distribution: temurin - java-version: 17 - - name: login to ${{ env.registry }} - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d - with: - registry: ${{ env.registry }} - username: ${{ secrets.DOCKER_USER_RW }} - password: ${{ secrets.DOCKER_PASSWORD_RW }} - - name: build image - uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 - with: - arguments: distDocker -PdockerOrgName=${{ env.registry }}/${{ github.repository_owner }} -Pbranch=main - - name: install goss - run: | - mkdir -p docker/reports - curl -L https://github.com/aelsabbahy/goss/releases/download/v0.4.4/goss-${{ steps.prep.outputs.PLATFORM_PAIR }} -o ./docker/tests/goss-${{ steps.prep.outputs.PLATFORM_PAIR }} - - name: test docker - uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 - env: - architecture: ${{ steps.prep.outputs.ARCH }} - with: - arguments: testDocker -PdockerOrgName=${{ env.registry }}/${{ github.repository_owner }} -Pbranch=main - - name: login to $ {{ env.registry }} - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d - with: - registry: ${{ env.registry }} - username: ${{ secrets.DOCKER_USER_RW }} - password: ${{ secrets.DOCKER_PASSWORD_RW }} - - name: publish - env: - architecture: ${{ steps.prep.outputs.ARCH }} - run: ./gradlew --no-daemon dockerUpload -PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }} -Pbranch=main - multiArch: - permissions: - contents: read - packages: write - needs: buildDocker - runs-on: ubuntu-22.04 - steps: - - name: Checkout Repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - - name: Set up Java - uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 - with: - distribution: temurin - java-version: 17 - - name: setup gradle - uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 - - name: Login to ${{ env.registry }} - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d - with: - registry: ${{ env.registry }} - username: ${{ secrets.DOCKER_USER_RW }} - password: ${{ secrets.DOCKER_PASSWORD_RW }} - - name: multi-arch docker - run: ./gradlew manifestDocker -PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }} -Pbranch=main - diff --git a/.github/workflows/pre-review.yml b/.github/workflows/pre-review.yml index 0d3a3e6c900..b3adc7c42cd 100644 --- a/.github/workflows/pre-review.yml +++ b/.github/workflows/pre-review.yml @@ -6,6 +6,13 @@ on: - main - release-* +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + GRADLE_OPTS: "-Xmx6g -Dorg.gradle.daemon=false -Dorg.gradle.parallel=true" + jobs: repolint: name: "Repository Linting" @@ -41,8 +48,10 @@ jobs: java-version: 17 - name: Setup Gradle uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 + with: + cache-disabled: true - name: run spotless - run: ./gradlew spotlessCheck -Dorg.gradle.parallel=true -Dorg.gradle.caching=true + run: ./gradlew spotlessCheck compile: runs-on: ubuntu-22.04 timeout-minutes: 30 @@ -59,8 +68,10 @@ jobs: java-version: 17 - name: Setup Gradle uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 + with: + cache-disabled: true - name: Gradle Compile - run: ./gradlew build -x test -x spotlessCheck -Dorg.gradle.parallel=true -Dorg.gradle.caching=true + run: ./gradlew build -x test -x spotlessCheck unitTests: env: GRADLEW_UNIT_TEST_ARGS: ${{matrix.gradle_args}} @@ -92,9 +103,11 @@ jobs: java-version: 17 - name: Setup Gradle uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 + with: + cache-disabled: true - name: run unit tests id: unitTest - run: ./gradlew $GRADLEW_UNIT_TEST_ARGS -Dorg.gradle.parallel=true -Dorg.gradle.caching=true + run: ./gradlew $GRADLEW_UNIT_TEST_ARGS - name: Publish Test Report uses: mikepenz/action-junit-report@5f47764eec0e1c1f19f40c8e60a5ba47e47015c5 if: success() || failure() # always run even if the build step fails @@ -102,6 +115,7 @@ jobs: report_paths: '**/test-results/**/TEST-*.xml' annotate_only: true unittests-passed: + name: "unittests-passed" runs-on: ubuntu-22.04 needs: [unitTests] permissions: diff --git a/.github/workflows/reference-tests.yml b/.github/workflows/reference-tests.yml index ccb03632db3..f9dd87c4589 100644 --- a/.github/workflows/reference-tests.yml +++ b/.github/workflows/reference-tests.yml @@ -5,63 +5,22 @@ on: branches: - main - release-* - pull_request_review: - types: [ submitted ] env: - GRADLE_OPTS: "-Xmx6g -Dorg.gradle.daemon=false" + GRADLE_OPTS: "-Xmx6g -Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.caching=true" total-runners: 10 -jobs: - shouldRun: - name: checks to ensure we should run - # necessary because there is no single PR approved event, need to check all comments/approvals/denials - # might also be a job running, and additional approvals - runs-on: ubuntu-22.04 - outputs: - shouldRun: ${{steps.shouldRun.outputs.result}} - steps: - - name: required check - id: shouldRun - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea - env: - # fun fact, this changes based on incoming event, it will be different when we run this on pushes to main - RELEVANT_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - with: - script: | - const { RELEVANT_SHA } = process.env; - const { data: { statuses } } = await github.rest.repos.getCombinedStatusForRef({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: RELEVANT_SHA, - }); - - - const refTested = statuses && statuses.filter(({ context }) => context === 'reftests-passed'); - const alreadyRun = refTested && refTested.find(({ state }) => state === 'success') > 0; - const { data: reviews } = await github.rest.pulls.listReviews({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.issue.number, - }); - const approvingReviews = reviews && reviews.filter(review => review.state === 'APPROVED'); - const shouldRun = !alreadyRun && github.actor != 'dependabot[bot]' && (approvingReviews.length > 0); - - console.log("tests should be run = %j", shouldRun); - console.log("alreadyRun = %j", alreadyRun); - console.log("approvingReviews = %j", approvingReviews.length); - - return shouldRun; +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true +jobs: referenceTestEthereum: runs-on: ubuntu-22.04 permissions: statuses: write checks: write packages: read - needs: - - shouldRun - if: ${{ needs.shouldRun.outputs.shouldRun == 'true' }} strategy: fail-fast: true matrix: @@ -79,7 +38,8 @@ jobs: java-version: 17 - name: setup gradle uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 - #shame the test generation isn't less redundant, we used to do this in a dependent job, but artifact downloading broke + with: + cache-disabled: true - name: execute generate reference tests run: ./gradlew ethereum:referencetests:blockchainReferenceTests ethereum:referencetests:generalstateReferenceTests ethereum:referencetests:generalstateRegressionReferenceTests -Dorg.gradle.parallel=true -Dorg.gradle.caching=true - name: list test files generated @@ -95,7 +55,7 @@ jobs: - name: refTestArgs.txt run: cat refTestArgs.txt - name: run reference tests - run: ./gradlew ethereum:referenceTests:referenceTests `cat refTestArgs.txt` -Dorg.gradle.parallel=true -Dorg.gradle.caching=true + run: ./gradlew ethereum:referenceTests:referenceTests `cat refTestArgs.txt` - name: Upload Test Report uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 if: always() # always run even if the previous step fails @@ -109,6 +69,7 @@ jobs: report_paths: '**/build/test-results/referenceTests/TEST-*.xml' annotate_only: true reftests-passed: + name: "reftests-passed" runs-on: ubuntu-22.04 needs: [ referenceTestEthereum ] permissions: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ceb8ba602cb..3ae4a0ddf8d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,5 @@ name: release besu on: - workflow_dispatch: release: types: [released] env: @@ -23,6 +22,8 @@ jobs: password: ${{ secrets.DOCKER_PASSWORD_RW }} - name: Setup Gradle uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 + with: + cache-disabled: true - name: Docker upload run: ./gradlew "-Prelease.releaseVersion=${{ github.ref_name }}" "-PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }}" dockerUploadRelease - name: Docker manifest diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 7891a6819db..3ef37c1dafa 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -30,6 +30,8 @@ jobs: restore-keys: ${{ runner.os }}-sonar - name: setup gradle uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 + with: + cache-disabled: true - name: Build and analyze env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any From c39ca6d44f40a4f122e05b186a211857ec17138e Mon Sep 17 00:00:00 2001 From: garyschulte Date: Tue, 12 Mar 2024 18:19:37 -0700 Subject: [PATCH 08/11] Support pruned chain history in peer validators (#6698) * dao fork block presence is optional in peer validator to support peers with pruned chain history Signed-off-by: garyschulte * Update ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/peervalidation/AbstractPeerBlockValidator.java Co-authored-by: Sally MacFarlane Signed-off-by: garyschulte --------- Signed-off-by: garyschulte Co-authored-by: Sally MacFarlane --- .../AbstractPeerBlockValidator.java | 24 ++++++++++++++----- .../peervalidation/DaoForkPeerValidator.java | 9 +++++++ .../DaoForkPeerValidatorTest.java | 24 +++++++++++++++++++ .../RequiredBlocksPeerValidatorTest.java | 22 +++++++++++++++++ 4 files changed, 73 insertions(+), 6 deletions(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/peervalidation/AbstractPeerBlockValidator.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/peervalidation/AbstractPeerBlockValidator.java index 55c3dd89e56..4483e14cdfa 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/peervalidation/AbstractPeerBlockValidator.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/peervalidation/AbstractPeerBlockValidator.java @@ -86,12 +86,20 @@ public CompletableFuture validatePeer( } final List headers = res.getResult(); if (headers.size() == 0) { - // If no headers are returned, fail - LOG.debug( - "Peer {} is invalid because required block ({}) is unavailable.", - ethPeer, - blockNumber); - return false; + if (blockIsRequired()) { + // If no headers are returned, fail + LOG.debug( + "Peer {} is invalid because required block ({}) is unavailable.", + ethPeer, + blockNumber); + return false; + } else { + LOG.debug( + "Peer {} deemed valid because unavailable block ({}) is not required.", + ethPeer, + blockNumber); + return true; + } } final BlockHeader header = headers.get(0); return validateBlockHeader(ethPeer, header); @@ -105,6 +113,10 @@ public boolean canBeValidated(final EthPeer ethPeer) { return ethPeer.chainState().getEstimatedHeight() >= (blockNumber + chainHeightEstimationBuffer); } + protected boolean blockIsRequired() { + return true; + } + @Override public Duration nextValidationCheckTimeout(final EthPeer ethPeer) { if (!ethPeer.chainState().hasEstimatedHeight()) { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/peervalidation/DaoForkPeerValidator.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/peervalidation/DaoForkPeerValidator.java index d038ad0e9a9..01ce6144ee0 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/peervalidation/DaoForkPeerValidator.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/peervalidation/DaoForkPeerValidator.java @@ -49,4 +49,13 @@ boolean validateBlockHeader(final EthPeer ethPeer, final BlockHeader header) { } return validDaoBlock; } + + /** + * In order to support chain history pruning, clients do not need to have the dao fork block to be + * deemed valid. + */ + @Override + protected boolean blockIsRequired() { + return false; + } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/DaoForkPeerValidatorTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/DaoForkPeerValidatorTest.java index 8586874c434..042ca8f9605 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/DaoForkPeerValidatorTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/DaoForkPeerValidatorTest.java @@ -98,4 +98,28 @@ public void validatePeer_responsivePeerOnWrongSideOfFork() { assertThat(result).isDone(); assertThat(result).isCompletedWithValue(false); } + + @Test + public void validatePeer_responsivePeerDoesNotHaveBlockWhenPastForkHeight() { + final EthProtocolManager ethProtocolManager = EthProtocolManagerTestUtil.create(); + final long daoBlockNumber = 500; + + final PeerValidator validator = + new DaoForkPeerValidator( + ProtocolScheduleFixture.MAINNET, new NoOpMetricsSystem(), daoBlockNumber, 0); + + final RespondingEthPeer peer = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, daoBlockNumber); + + final CompletableFuture result = + validator.validatePeer(ethProtocolManager.ethContext(), peer.getEthPeer()); + + assertThat(result).isNotDone(); + + // Respond to block header request with empty + peer.respond(RespondingEthPeer.emptyResponder()); + + assertThat(result).isDone(); + assertThat(result).isCompletedWithValue(true); + } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/RequiredBlocksPeerValidatorTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/RequiredBlocksPeerValidatorTest.java index 67c80345880..87b3c7077cc 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/RequiredBlocksPeerValidatorTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/peervalidation/RequiredBlocksPeerValidatorTest.java @@ -104,4 +104,26 @@ public void validatePeer_responsivePeerWithBadRequiredBlock() { assertThat(result).isDone(); assertThat(result).isCompletedWithValue(false); } + + @Test + public void validatePeer_responsivePeerDoesNotHaveBlockWhenPastForkHeight() { + final EthProtocolManager ethProtocolManager = EthProtocolManagerTestUtil.create(); + + final PeerValidator validator = + new RequiredBlocksPeerValidator( + ProtocolScheduleFixture.MAINNET, new NoOpMetricsSystem(), 1, Hash.ZERO); + + final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1); + + final CompletableFuture result = + validator.validatePeer(ethProtocolManager.ethContext(), peer.getEthPeer()); + + assertThat(result).isNotDone(); + + // Respond to block header request with empty + peer.respond(RespondingEthPeer.emptyResponder()); + + assertThat(result).isDone(); + assertThat(result).isCompletedWithValue(false); + } } From 501d169db5b2dfc95339d8813d0ae4aa336c6445 Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Wed, 13 Mar 2024 12:08:24 +1000 Subject: [PATCH 09/11] edits to changelog for 24.3.0 (#6712) Signed-off-by: Sally MacFarlane --- CHANGELOG.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee32ad05f85..6141beee13f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Breaking Changes - RocksDB database metadata format has changed to be more expressive, the migration of an existing metadata file to the new format is automatic at startup. Before performing a downgrade to a previous version it is mandatory to revert to the original format using the subcommand `besu --data-path=/path/to/besu/datadir storage revert-metadata v2-to-v1`. -- PoA networks won't start with SNAP or CHECKPOINT sync (previously Besu would start with this config but quietly fail to sync, so it's now more obvious that it won't work) [#6625](https://github.com/hyperledger/besu/pull/6625) +- BFT networks won't start with SNAP or CHECKPOINT sync (previously Besu would start with this config but quietly fail to sync, so it's now more obvious that it won't work) [#6625](https://github.com/hyperledger/besu/pull/6625), [#6667](https://github.com/hyperledger/besu/pull/6667) ### Upcoming Breaking Changes @@ -18,8 +18,6 @@ - Make layered txpool aware of minGasPrice and minPriorityFeePerGas dynamic options [#6611](https://github.com/hyperledger/besu/pull/6611) - Update commons-compress to 1.26.0 [#6648](https://github.com/hyperledger/besu/pull/6648) - Update Vert.x to 4.5.4 [#6666](https://github.com/hyperledger/besu/pull/6666) -- Add blob transaction support to `eth_call` [#6661](https://github.com/hyperledger/besu/pull/6661) -- Add blobs to `eth_feeHistory` [#6679](https://github.com/hyperledger/besu/pull/6679) - Refactor and extend `TransactionPoolValidatorService` [#6636](https://github.com/hyperledger/besu/pull/6636) - Transaction call object to accept both `input` and `data` field simultaneously if they are set to equal values [#6702](https://github.com/hyperledger/besu/pull/6702) @@ -29,7 +27,7 @@ ### Download Links -## 24.2.0-SNAPSHOT +## 24.3.0 ### Breaking Changes - SNAP - Snap sync is now the default for named networks [#6530](https://github.com/hyperledger/besu/pull/6530) @@ -46,7 +44,7 @@ - Release docker images now provided at ghcr.io instead of dockerhub ### Deprecations -- X_SNAP and X_CHECKPOINT are marked for deprecation and will be removed in 24.4.0 in favor of SNAP and CHECKPOINT [#6405](https://github.com/hyperledger/besu/pull/6405) +- X_SNAP and X_CHECKPOINT are marked for deprecation and will be removed in 24.6.0 in favor of SNAP and CHECKPOINT [#6405](https://github.com/hyperledger/besu/pull/6405) - `--Xp2p-peer-lower-bound` is deprecated. [#6501](https://github.com/hyperledger/besu/pull/6501) ### Upcoming Breaking Changes @@ -73,6 +71,8 @@ - More accurate column size `storage rocksdb usage` subcommand [#6540](https://github.com/hyperledger/besu/pull/6540) - Adds `storage rocksdb x-stats` subcommand [#6540](https://github.com/hyperledger/besu/pull/6540) - New `eth_blobBaseFee`JSON-RPC method [#6581](https://github.com/hyperledger/besu/pull/6581) +- Add blob transaction support to `eth_call` [#6661](https://github.com/hyperledger/besu/pull/6661) +- Add blobs to `eth_feeHistory` [#6679](https://github.com/hyperledger/besu/pull/6679) - Upgrade reference tests to version 13.1 [#6574](https://github.com/hyperledger/besu/pull/6574) - Extend `BesuConfiguration` service [#6584](https://github.com/hyperledger/besu/pull/6584) - Add `ethereum_min_gas_price` and `ethereum_min_priority_fee` metrics to track runtime values of `min-gas-price` and `min-priority-fee` [#6587](https://github.com/hyperledger/besu/pull/6587) @@ -86,6 +86,9 @@ - Fix traces so that call gas costing in traces matches other clients traces [#6525](https://github.com/hyperledger/besu/pull/6525) ### Download Links +https://github.com/hyperledger/besu/releases/tag/24.3.0 +https://github.com/hyperledger/besu/releases/download/24.3.0/besu-24.3.0.tar.gz / sha256 8037ce51bb5bb396d29717a812ea7ff577b0d6aa341d67d1e5b77cbc55b15f84 +https://github.com/hyperledger/besu/releases/download/24.3.0/besu-24.3.0.zip / sha256 41ea2ca734a3b377f43ee178166b5b809827084789378dbbe4e5b52bbd8e0674 ## 24.1.2 From 602999f4cff6960ba29da41d76a932f5166d8601 Mon Sep 17 00:00:00 2001 From: Usman Saleem Date: Wed, 13 Mar 2024 13:01:00 +1000 Subject: [PATCH 10/11] Refactor BadBlockReason enum out of BadBlockCause (#6716) * Refactor BadBlockReason enum out of BadBlockCause Signed-off-by: Usman Saleem * Deleting ununsed enum value Signed-off-by: Usman Saleem --------- Signed-off-by: Usman Saleem Co-authored-by: Sally MacFarlane --- .../besu/ethereum/chain/BadBlockCause.java | 15 +++++-------- .../besu/ethereum/chain/BadBlockReason.java | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BadBlockReason.java diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BadBlockCause.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BadBlockCause.java index 7a014e99cd2..601e96de25f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BadBlockCause.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BadBlockCause.java @@ -15,19 +15,14 @@ */ package org.hyperledger.besu.ethereum.chain; +import static org.hyperledger.besu.ethereum.chain.BadBlockReason.DESCENDS_FROM_BAD_BLOCK; +import static org.hyperledger.besu.ethereum.chain.BadBlockReason.SPEC_VALIDATION_FAILURE; + import org.hyperledger.besu.ethereum.core.Block; import com.google.common.base.MoreObjects; public class BadBlockCause { - public enum BadBlockReason { - // Standard spec-related validation failures - SPEC_VALIDATION_FAILURE, - // When an unexpected exception occurs during block processing - EXCEPTIONAL_BLOCK_PROCESSING, - // This block is bad because it descends from a bad block - DESCENDS_FROM_BAD_BLOCK, - } private final BadBlockReason reason; private final String description; @@ -35,11 +30,11 @@ public enum BadBlockReason { public static BadBlockCause fromBadAncestorBlock(final Block badAncestor) { final String description = String.format("Descends from bad block %s", badAncestor.toLogString()); - return new BadBlockCause(BadBlockReason.DESCENDS_FROM_BAD_BLOCK, description); + return new BadBlockCause(DESCENDS_FROM_BAD_BLOCK, description); } public static BadBlockCause fromValidationFailure(final String failureMessage) { - return new BadBlockCause(BadBlockReason.SPEC_VALIDATION_FAILURE, failureMessage); + return new BadBlockCause(SPEC_VALIDATION_FAILURE, failureMessage); } private BadBlockCause(final BadBlockReason reason, final String description) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BadBlockReason.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BadBlockReason.java new file mode 100644 index 00000000000..f38655cb830 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BadBlockReason.java @@ -0,0 +1,22 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.chain; + +public enum BadBlockReason { + // Standard spec-related validation failures + SPEC_VALIDATION_FAILURE, + // This block is bad because it descends from a bad block + DESCENDS_FROM_BAD_BLOCK, +} From e56a37da110e78a843460f6d6580521b787401cb Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Wed, 13 Mar 2024 14:26:48 +1000 Subject: [PATCH 11/11] verify syncing false (#6720) Signed-off-by: Sally MacFarlane --- .../jsonrpc/EthSendRawTransactionAcceptanceTest.java | 4 ++++ .../pubsub/NewPendingTransactionAcceptanceTest.java | 3 +++ 2 files changed, 7 insertions(+) diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/EthSendRawTransactionAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/EthSendRawTransactionAcceptanceTest.java index 4e4330da03b..c054a2a1653 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/EthSendRawTransactionAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/EthSendRawTransactionAcceptanceTest.java @@ -44,6 +44,10 @@ public void setUp() throws Exception { strictNode = besu.createArchiveNode("strictNode", configureNode((true))); miningNode = besu.createMinerNode("strictMiningNode", configureNode((true))); cluster.start(lenientNode, strictNode, miningNode); + // verify all nodes are done syncing so the tx pool will be enabled + lenientNode.verify(eth.syncingStatus(false)); + strictNode.verify(eth.syncingStatus(false)); + miningNode.verify(eth.syncingStatus(false)); } @Test diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/pubsub/NewPendingTransactionAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/pubsub/NewPendingTransactionAcceptanceTest.java index 4ae94924b25..9c0368abb88 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/pubsub/NewPendingTransactionAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/pubsub/NewPendingTransactionAcceptanceTest.java @@ -44,6 +44,9 @@ public void setUp() throws Exception { accountOne = accounts.createAccount("account-one"); minerWebSocket = new WebSocket(vertx, minerNode.getConfiguration()); archiveWebSocket = new WebSocket(vertx, archiveNode.getConfiguration()); + // verify all nodes are done syncing so the tx pool will be enabled + archiveNode.verify(eth.syncingStatus(false)); + minerNode.verify(eth.syncingStatus(false)); } @AfterEach