From e1f44897411eaa8a11a87c23c381090bb6ed18b1 Mon Sep 17 00:00:00 2001 From: Jason Frame Date: Fri, 20 Sep 2024 16:07:27 +1000 Subject: [PATCH 01/12] Disable body validation for POS networks during sync (#7646) Signed-off-by: Jason Frame Co-authored-by: Stefan Pingel <16143240+pinges@users.noreply.github.com> --- .../besu/ethereum/BlockValidator.java | 11 +- .../besu/ethereum/MainnetBlockValidator.java | 8 +- .../besu/ethereum/core/BlockImporter.java | 6 +- .../mainnet/BaseFeeBlockBodyValidator.java | 6 +- .../ethereum/mainnet/BlockBodyValidator.java | 3 +- .../ethereum/mainnet/BodyValidationMode.java | 26 ++++ .../mainnet/MainnetBlockBodyValidator.java | 34 +++-- .../mainnet/MainnetBlockImporter.java | 10 +- .../ethereum/MainnetBlockValidatorTest.java | 44 ++++--- .../MainnetBlockBodyValidatorTest.java | 123 +++++++++++++++++- .../mainnet/PragueRequestsValidatorTest.java | 3 +- .../FastSyncDownloadPipelineFactory.java | 8 +- .../eth/sync/fastsync/ImportBlocksStep.java | 14 +- .../sync/fastsync/ImportBlocksStepTest.java | 18 ++- 14 files changed, 255 insertions(+), 59 deletions(-) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidationMode.java diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/BlockValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/BlockValidator.java index e8136062bb..8cfafee730 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/BlockValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/BlockValidator.java @@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.Request; import org.hyperledger.besu.ethereum.core.TransactionReceipt; +import org.hyperledger.besu.ethereum.mainnet.BodyValidationMode; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import java.util.List; @@ -83,8 +84,8 @@ public interface BlockValidator { final boolean shouldRecordBadBlock); /** - * Performs fast block validation with the given context, block, transaction receipts, requests, - * header validation mode, and ommer validation mode. + * Performs fast block validation appropriate for use during syncing skipping transaction receipt + * roots and receipts roots as these are done during the download of the blocks. * * @param context the protocol context * @param block the block to validate @@ -92,13 +93,15 @@ public interface BlockValidator { * @param requests the requests * @param headerValidationMode the header validation mode * @param ommerValidationMode the ommer validation mode + * @param bodyValidationMode the body validation mode * @return true if the block is valid, false otherwise */ - boolean fastBlockValidation( + boolean validateBlockForSyncing( final ProtocolContext context, final Block block, final List receipts, final Optional> requests, final HeaderValidationMode headerValidationMode, - final HeaderValidationMode ommerValidationMode); + final HeaderValidationMode ommerValidationMode, + final BodyValidationMode bodyValidationMode); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/MainnetBlockValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/MainnetBlockValidator.java index 5d80a95150..0c56a419e3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/MainnetBlockValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/MainnetBlockValidator.java @@ -25,6 +25,7 @@ import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.mainnet.BlockBodyValidator; import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator; import org.hyperledger.besu.ethereum.mainnet.BlockProcessor; +import org.hyperledger.besu.ethereum.mainnet.BodyValidationMode; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.plugin.services.exception.StorageException; @@ -247,13 +248,14 @@ public class MainnetBlockValidator implements BlockValidator { } @Override - public boolean fastBlockValidation( + public boolean validateBlockForSyncing( final ProtocolContext context, final Block block, final List receipts, final Optional> requests, final HeaderValidationMode headerValidationMode, - final HeaderValidationMode ommerValidationMode) { + final HeaderValidationMode ommerValidationMode, + final BodyValidationMode bodyValidationMode) { final BlockHeader header = block.getHeader(); if (!blockHeaderValidator.validateHeader(header, context, headerValidationMode)) { String description = String.format("Failed header validation (%s)", headerValidationMode); @@ -262,7 +264,7 @@ public class MainnetBlockValidator implements BlockValidator { } if (!blockBodyValidator.validateBodyLight( - context, block, receipts, requests, ommerValidationMode)) { + context, block, receipts, requests, ommerValidationMode, bodyValidationMode)) { badBlockManager.addBadBlock( block, BadBlockCause.fromValidationFailure("Failed body validation (light)")); return false; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockImporter.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockImporter.java index ce5c849e3a..468485b9fd 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockImporter.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockImporter.java @@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.core; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.mainnet.BlockImportResult; +import org.hyperledger.besu.ethereum.mainnet.BodyValidationMode; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import java.util.List; @@ -73,10 +74,11 @@ public interface BlockImporter { * @return {@code BlockImportResult} * @see BlockImportResult */ - BlockImportResult fastImportBlock( + BlockImportResult importBlockForSyncing( ProtocolContext context, Block block, List receipts, HeaderValidationMode headerValidationMode, - HeaderValidationMode ommerValidationMode); + HeaderValidationMode ommerValidationMode, + BodyValidationMode bodyValidationMode); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BaseFeeBlockBodyValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BaseFeeBlockBodyValidator.java index 0e288185cf..aabc4ee5d0 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BaseFeeBlockBodyValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BaseFeeBlockBodyValidator.java @@ -43,9 +43,11 @@ public class BaseFeeBlockBodyValidator extends MainnetBlockBodyValidator { final Block block, final List receipts, final Optional> requests, - final HeaderValidationMode ommerValidationMode) { + final HeaderValidationMode ommerValidationMode, + final BodyValidationMode bodyValidationMode) { - return super.validateBodyLight(context, block, receipts, requests, ommerValidationMode) + return super.validateBodyLight( + context, block, receipts, requests, ommerValidationMode, bodyValidationMode) && validateTransactionGasPrice(block); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BlockBodyValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BlockBodyValidator.java index 62b4985f5c..c84be3771b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BlockBodyValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BlockBodyValidator.java @@ -59,5 +59,6 @@ public interface BlockBodyValidator { Block block, List receipts, final Optional> requests, - final HeaderValidationMode ommerValidationMode); + final HeaderValidationMode ommerValidationMode, + final BodyValidationMode bodyValidationMode); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidationMode.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidationMode.java new file mode 100644 index 0000000000..344a950e36 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidationMode.java @@ -0,0 +1,26 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.mainnet; + +public enum BodyValidationMode { + /** No Validation. data must be pre-validated */ + NONE, + + /** Skip receipts and transactions root validation */ + LIGHT, + + /** Fully validate the body */ + FULL; +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockBodyValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockBodyValidator.java index 3202440dd8..68951f9f2a 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockBodyValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockBodyValidator.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import com.google.common.annotations.VisibleForTesting; import org.apache.tuweni.bytes.Bytes32; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,7 +56,8 @@ public class MainnetBlockBodyValidator implements BlockBodyValidator { final Hash worldStateRootHash, final HeaderValidationMode ommerValidationMode) { - if (!validateBodyLight(context, block, receipts, requests, ommerValidationMode)) { + if (!validateBodyLight( + context, block, receipts, requests, ommerValidationMode, BodyValidationMode.FULL)) { return false; } @@ -77,18 +79,26 @@ public class MainnetBlockBodyValidator implements BlockBodyValidator { final Block block, final List receipts, final Optional> requests, - final HeaderValidationMode ommerValidationMode) { + final HeaderValidationMode ommerValidationMode, + final BodyValidationMode bodyValidationMode) { + if (bodyValidationMode == BodyValidationMode.NONE) { + return true; + } + final BlockHeader header = block.getHeader(); final BlockBody body = block.getBody(); - final Bytes32 transactionsRoot = BodyValidation.transactionsRoot(body.getTransactions()); - if (!validateTransactionsRoot(header, header.getTransactionsRoot(), transactionsRoot)) { - return false; - } + // these checks are only needed for full validation and can be skipped for light validation + if (bodyValidationMode == BodyValidationMode.FULL) { + final Bytes32 transactionsRoot = BodyValidation.transactionsRoot(body.getTransactions()); + if (!validateTransactionsRoot(header, header.getTransactionsRoot(), transactionsRoot)) { + return false; + } - final Bytes32 receiptsRoot = BodyValidation.receiptsRoot(receipts); - if (!validateReceiptsRoot(header, header.getReceiptsRoot(), receiptsRoot)) { - return false; + final Bytes32 receiptsRoot = BodyValidation.receiptsRoot(receipts); + if (!validateReceiptsRoot(header, header.getReceiptsRoot(), receiptsRoot)) { + return false; + } } final long gasUsed = @@ -115,7 +125,8 @@ public class MainnetBlockBodyValidator implements BlockBodyValidator { return true; } - private static boolean validateTransactionsRoot( + @VisibleForTesting + protected boolean validateTransactionsRoot( final BlockHeader header, final Bytes32 expected, final Bytes32 actual) { if (!expected.equals(actual)) { LOG.info( @@ -157,7 +168,8 @@ public class MainnetBlockBodyValidator implements BlockBodyValidator { return true; } - private static boolean validateReceiptsRoot( + @VisibleForTesting + protected boolean validateReceiptsRoot( final BlockHeader header, final Bytes32 expected, final Bytes32 actual) { if (!expected.equals(actual)) { LOG.warn( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockImporter.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockImporter.java index 62b708d33e..8646467a28 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockImporter.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockImporter.java @@ -57,20 +57,22 @@ public class MainnetBlockImporter implements BlockImporter { } @Override - public BlockImportResult fastImportBlock( + public BlockImportResult importBlockForSyncing( final ProtocolContext context, final Block block, final List receipts, final HeaderValidationMode headerValidationMode, - final HeaderValidationMode ommerValidationMode) { + final HeaderValidationMode ommerValidationMode, + final BodyValidationMode bodyValidationMode) { - if (blockValidator.fastBlockValidation( + if (blockValidator.validateBlockForSyncing( context, block, receipts, block.getBody().getRequests(), headerValidationMode, - ommerValidationMode)) { + ommerValidationMode, + bodyValidationMode)) { context.getBlockchain().appendBlock(block, receipts); return new BlockImportResult(true); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/MainnetBlockValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/MainnetBlockValidatorTest.java index 361353ee2b..40573ee8d6 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/MainnetBlockValidatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/MainnetBlockValidatorTest.java @@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.mainnet.BlockBodyValidator; import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator; import org.hyperledger.besu.ethereum.mainnet.BlockProcessor; +import org.hyperledger.besu.ethereum.mainnet.BodyValidationMode; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; @@ -98,7 +99,8 @@ public class MainnetBlockValidatorTest { when(blockHeaderValidator.validateHeader(any(), any(), any(), any())).thenReturn(true); when(blockBodyValidator.validateBody(any(), any(), any(), any(), any(), any())) .thenReturn(true); - when(blockBodyValidator.validateBodyLight(any(), any(), any(), any(), any())).thenReturn(true); + when(blockBodyValidator.validateBodyLight(any(), any(), any(), any(), any(), any())) + .thenReturn(true); when(blockProcessor.processBlock(any(), any(), any())).thenReturn(successfulProcessingResult); when(blockProcessor.processBlock(any(), any(), any(), any())) .thenReturn(successfulProcessingResult); @@ -343,55 +345,65 @@ public class MainnetBlockValidatorTest { } @Test - public void fastBlockValidation_onSuccess() { + public void validateBlockForSyncing_onSuccess() { final boolean isValid = - mainnetBlockValidator.fastBlockValidation( + mainnetBlockValidator.validateBlockForSyncing( protocolContext, block, Collections.emptyList(), block.getBody().getRequests(), HeaderValidationMode.FULL, - HeaderValidationMode.FULL); + HeaderValidationMode.FULL, + BodyValidationMode.FULL); assertThat(isValid).isTrue(); assertNoBadBlocks(); } @Test - public void fastBlockValidation_onFailedHeaderValidation() { - final HeaderValidationMode validationMode = HeaderValidationMode.FULL; + public void validateBlockValidation_onFailedHeaderForSyncing() { + final HeaderValidationMode headerValidationMode = HeaderValidationMode.FULL; when(blockHeaderValidator.validateHeader( - any(BlockHeader.class), eq(protocolContext), eq(validationMode))) + any(BlockHeader.class), eq(protocolContext), eq(headerValidationMode))) .thenReturn(false); + final BodyValidationMode bodyValidationMode = BodyValidationMode.FULL; final boolean isValid = - mainnetBlockValidator.fastBlockValidation( + mainnetBlockValidator.validateBlockForSyncing( protocolContext, block, Collections.emptyList(), block.getBody().getRequests(), - validationMode, - validationMode); + headerValidationMode, + headerValidationMode, + bodyValidationMode); assertThat(isValid).isFalse(); assertBadBlockIsTracked(block); } @Test - public void fastBlockValidation_onFailedBodyValidation() { - final HeaderValidationMode validationMode = HeaderValidationMode.FULL; + public void validateBlockValidation_onFailedBodyForSyncing() { + final HeaderValidationMode headerValidationMode = HeaderValidationMode.FULL; + final BodyValidationMode bodyValidationMode = BodyValidationMode.FULL; when(blockBodyValidator.validateBodyLight( - eq(protocolContext), eq(block), any(), any(), eq(validationMode))) + eq(protocolContext), + eq(block), + any(), + any(), + eq(headerValidationMode), + eq(bodyValidationMode))) .thenReturn(false); final boolean isValid = - mainnetBlockValidator.fastBlockValidation( + mainnetBlockValidator.validateBlockForSyncing( protocolContext, block, Collections.emptyList(), block.getBody().getRequests(), - validationMode, - validationMode); + headerValidationMode, + headerValidationMode, + bodyValidationMode); assertThat(isValid).isFalse(); assertBadBlockIsTracked(block); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockBodyValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockBodyValidatorTest.java index c116d545d8..c412a30756 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockBodyValidatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockBodyValidatorTest.java @@ -19,14 +19,22 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode.NONE; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.GWei; +import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockDataGenerator.BlockOptions; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; +import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.mainnet.requests.DepositRequestValidator; import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidatorCoordinator; @@ -93,7 +101,12 @@ class MainnetBlockBodyValidatorTest { assertThat( new MainnetBlockBodyValidator(protocolSchedule) .validateBodyLight( - blockchainSetupUtil.getProtocolContext(), block, emptyList(), any(), NONE)) + blockchainSetupUtil.getProtocolContext(), + block, + emptyList(), + any(), + NONE, + BodyValidationMode.FULL)) .isTrue(); } @@ -117,7 +130,12 @@ class MainnetBlockBodyValidatorTest { assertThat( new MainnetBlockBodyValidator(protocolSchedule) .validateBodyLight( - blockchainSetupUtil.getProtocolContext(), block, emptyList(), any(), NONE)) + blockchainSetupUtil.getProtocolContext(), + block, + emptyList(), + any(), + NONE, + BodyValidationMode.FULL)) .isFalse(); } @@ -141,7 +159,12 @@ class MainnetBlockBodyValidatorTest { assertThat( new MainnetBlockBodyValidator(protocolSchedule) .validateBodyLight( - blockchainSetupUtil.getProtocolContext(), block, emptyList(), any(), NONE)) + blockchainSetupUtil.getProtocolContext(), + block, + emptyList(), + any(), + NONE, + BodyValidationMode.FULL)) .isFalse(); } @@ -165,7 +188,99 @@ class MainnetBlockBodyValidatorTest { assertThat( new MainnetBlockBodyValidator(protocolSchedule) .validateBodyLight( - blockchainSetupUtil.getProtocolContext(), block, emptyList(), any(), NONE)) + blockchainSetupUtil.getProtocolContext(), + block, + emptyList(), + any(), + NONE, + BodyValidationMode.FULL)) .isFalse(); } + + @Test + @SuppressWarnings("unchecked") + public void noneValidationModeDoesNothing() { + final Block block = mock(Block.class); + final List receipts = mock(List.class); + + final MainnetBlockBodyValidator bodyValidator = new MainnetBlockBodyValidator(protocolSchedule); + + assertThat( + bodyValidator.validateBodyLight( + blockchainSetupUtil.getProtocolContext(), + block, + receipts, + Optional.empty(), + NONE, + BodyValidationMode.NONE)) + .isTrue(); + verifyNoInteractions(block); + verifyNoInteractions(receipts); + } + + @Test + public void lightValidationDoesNotCheckTransactionRootOrReceiptRoot() { + final Block block = + blockDataGenerator.block( + new BlockOptions() + .setBlockNumber(1) + .setGasUsed(0) + .hasTransactions(false) + .hasOmmers(false) + .setReceiptsRoot(BodyValidation.receiptsRoot(emptyList())) + .setLogsBloom(LogsBloomFilter.empty()) + .setParentHash(blockchainSetupUtil.getBlockchain().getChainHeadHash()) + .setWithdrawals(Optional.of(withdrawals))); + blockchainSetupUtil.getBlockchain().appendBlock(block, Collections.emptyList()); + + final MainnetBlockBodyValidator bodyValidator = new MainnetBlockBodyValidator(protocolSchedule); + final MainnetBlockBodyValidator bodyValidatorSpy = spy(bodyValidator); + + assertThat( + bodyValidatorSpy.validateBodyLight( + blockchainSetupUtil.getProtocolContext(), + block, + emptyList(), + Optional.empty(), + NONE, + BodyValidationMode.LIGHT)) + .isTrue(); + verify(bodyValidatorSpy, never()).validateReceiptsRoot(any(), any(), any()); + verify(bodyValidatorSpy, never()).validateTransactionsRoot(any(), any(), any()); + } + + @Test + public void fullValidationChecksTransactionRootAndReceiptRoot() { + final Block block = + blockDataGenerator.block( + new BlockOptions() + .setBlockNumber(1) + .setGasUsed(0) + .hasTransactions(false) + .hasOmmers(false) + .setReceiptsRoot(BodyValidation.receiptsRoot(emptyList())) + .setLogsBloom(LogsBloomFilter.empty()) + .setParentHash(blockchainSetupUtil.getBlockchain().getChainHeadHash()) + .setWithdrawals(Optional.of(withdrawals))); + blockchainSetupUtil.getBlockchain().appendBlock(block, Collections.emptyList()); + + final MainnetBlockBodyValidator bodyValidator = new MainnetBlockBodyValidator(protocolSchedule); + final MainnetBlockBodyValidator bodyValidatorSpy = spy(bodyValidator); + + assertThat( + bodyValidatorSpy.validateBodyLight( + blockchainSetupUtil.getProtocolContext(), + block, + emptyList(), + Optional.empty(), + NONE, + BodyValidationMode.FULL)) + .isTrue(); + final Hash receiptsRoot = BodyValidation.receiptsRoot(emptyList()); + final Hash transactionsRoot = BodyValidation.transactionsRoot(emptyList()); + verify(bodyValidatorSpy, times(1)) + .validateReceiptsRoot(block.getHeader(), receiptsRoot, receiptsRoot); + verify(bodyValidatorSpy, times(1)) + .validateTransactionsRoot(block.getHeader(), transactionsRoot, transactionsRoot); + } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PragueRequestsValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PragueRequestsValidatorTest.java index 833e692d7f..6c325b70a8 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PragueRequestsValidatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PragueRequestsValidatorTest.java @@ -106,7 +106,8 @@ class PragueRequestsValidatorTest { block, emptyList(), expectedRequests, - NONE)) + NONE, + BodyValidationMode.FULL)) .isFalse(); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloadPipelineFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloadPipelineFactory.java index 07e964426c..87032b76e5 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloadPipelineFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloadPipelineFactory.java @@ -37,6 +37,7 @@ import org.hyperledger.besu.ethereum.eth.sync.range.SyncTargetRange; import org.hyperledger.besu.ethereum.eth.sync.range.SyncTargetRangeSource; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.eth.sync.state.SyncTarget; +import org.hyperledger.besu.ethereum.mainnet.BodyValidationMode; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; @@ -117,6 +118,10 @@ public class FastSyncDownloadPipelineFactory implements DownloadPipelineFactory final int downloaderParallelism = syncConfig.getDownloaderParallelism(); final int headerRequestSize = syncConfig.getDownloaderHeaderRequestSize(); final int singleHeaderBufferSize = headerRequestSize * downloaderParallelism; + final BodyValidationMode bodyValidationMode = + protocolSchedule.anyMatch(scheduledProtocolSpec -> scheduledProtocolSpec.spec().isPoS()) + ? BodyValidationMode.NONE + : BodyValidationMode.LIGHT; final SyncTargetRangeSource checkpointRangeSource = new SyncTargetRangeSource( new RangeHeadersFetcher( @@ -148,7 +153,8 @@ public class FastSyncDownloadPipelineFactory implements DownloadPipelineFactory attachedValidationPolicy, ommerValidationPolicy, ethContext, - fastSyncState.getPivotBlockHeader().get()); + fastSyncState.getPivotBlockHeader().get(), + bodyValidationMode); return PipelineBuilder.createPipelineFrom( "fetchCheckpoints", diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/ImportBlocksStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/ImportBlocksStep.java index c6945964cf..20b9d84916 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/ImportBlocksStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/ImportBlocksStep.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.sync.ValidationPolicy; import org.hyperledger.besu.ethereum.eth.sync.tasks.exceptions.InvalidBlockException; import org.hyperledger.besu.ethereum.mainnet.BlockImportResult; +import org.hyperledger.besu.ethereum.mainnet.BodyValidationMode; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import java.util.List; @@ -45,6 +46,7 @@ public class ImportBlocksStep implements Consumer> { private long accumulatedTime = 0L; private OptionalLong logStartBlock = OptionalLong.empty(); private final BlockHeader pivotHeader; + private final BodyValidationMode bodyValidationMode; public ImportBlocksStep( final ProtocolSchedule protocolSchedule, @@ -52,13 +54,15 @@ public class ImportBlocksStep implements Consumer> { final ValidationPolicy headerValidationPolicy, final ValidationPolicy ommerValidationPolicy, final EthContext ethContext, - final BlockHeader pivotHeader) { + final BlockHeader pivotHeader, + final BodyValidationMode bodyValidationMode) { this.protocolSchedule = protocolSchedule; this.protocolContext = protocolContext; this.headerValidationPolicy = headerValidationPolicy; this.ommerValidationPolicy = ommerValidationPolicy; this.ethContext = ethContext; this.pivotHeader = pivotHeader; + this.bodyValidationMode = bodyValidationMode; } @Override @@ -106,20 +110,20 @@ public class ImportBlocksStep implements Consumer> { if (totalBlocks == 0) { return 0; } - final long blocksPercent = (100 * lastBlock / totalBlocks); - return blocksPercent; + return (100 * lastBlock / totalBlocks); } protected boolean importBlock(final BlockWithReceipts blockWithReceipts) { final BlockImporter importer = protocolSchedule.getByBlockHeader(blockWithReceipts.getHeader()).getBlockImporter(); final BlockImportResult blockImportResult = - importer.fastImportBlock( + importer.importBlockForSyncing( protocolContext, blockWithReceipts.getBlock(), blockWithReceipts.getReceipts(), headerValidationPolicy.getValidationModeForNextBlock(), - ommerValidationPolicy.getValidationModeForNextBlock()); + ommerValidationPolicy.getValidationModeForNextBlock(), + bodyValidationMode); return blockImportResult.isImported(); } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/ImportBlocksStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/ImportBlocksStepTest.java index 70c9e10eba..af4f45f690 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/ImportBlocksStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/ImportBlocksStepTest.java @@ -33,6 +33,7 @@ import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.eth.sync.ValidationPolicy; import org.hyperledger.besu.ethereum.eth.sync.tasks.exceptions.InvalidBlockException; import org.hyperledger.besu.ethereum.mainnet.BlockImportResult; +import org.hyperledger.besu.ethereum.mainnet.BodyValidationMode; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; @@ -72,7 +73,8 @@ public class ImportBlocksStepTest { validationPolicy, ommerValidationPolicy, null, - pivotHeader); + pivotHeader, + BodyValidationMode.FULL); } @Test @@ -84,12 +86,13 @@ public class ImportBlocksStepTest { .collect(toList()); for (final BlockWithReceipts blockWithReceipts : blocksWithReceipts) { - when(blockImporter.fastImportBlock( + when(blockImporter.importBlockForSyncing( protocolContext, blockWithReceipts.getBlock(), blockWithReceipts.getReceipts(), FULL, - LIGHT)) + LIGHT, + BodyValidationMode.FULL)) .thenReturn(new BlockImportResult(true)); } importBlocksStep.accept(blocksWithReceipts); @@ -105,8 +108,13 @@ public class ImportBlocksStepTest { final Block block = gen.block(); final BlockWithReceipts blockWithReceipts = new BlockWithReceipts(block, gen.receipts(block)); - when(blockImporter.fastImportBlock( - protocolContext, block, blockWithReceipts.getReceipts(), FULL, LIGHT)) + when(blockImporter.importBlockForSyncing( + protocolContext, + block, + blockWithReceipts.getReceipts(), + FULL, + LIGHT, + BodyValidationMode.FULL)) .thenReturn(new BlockImportResult(false)); assertThatThrownBy(() -> importBlocksStep.accept(singletonList(blockWithReceipts))) .isInstanceOf(InvalidBlockException.class); From e721237c26b518d9b4f100b695df8ab7290034ee Mon Sep 17 00:00:00 2001 From: Matt Whitehead Date: Fri, 20 Sep 2024 09:38:57 +0100 Subject: [PATCH 02/12] Don't persist IBFT2 proposal blocks, just validate them (#7631) * Don't persist IBFT2 proposal blocks, just validate them Signed-off-by: Matthew Whitehead * Tidy up changelog Signed-off-by: Matthew Whitehead --------- Signed-off-by: Matthew Whitehead Signed-off-by: Matt Whitehead --- CHANGELOG.md | 2 +- .../hyperledger/besu/consensus/common/bft/RoundTimer.java | 2 +- .../besu/consensus/ibft/validation/MessageValidator.java | 8 +++++--- .../consensus/ibft/validation/MessageValidatorTest.java | 4 ++-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1ecca978e..246df1d91c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ - Fix mounted data path directory permissions for besu user [#7575](https://github.com/hyperledger/besu/pull/7575) - Fix for `debug_traceCall` to handle transactions without specified gas price. [#7510](https://github.com/hyperledger/besu/pull/7510) - Corrects a regression where custom plugin services are not initialized correctly. [#7625](https://github.com/hyperledger/besu/pull/7625) - +- Fix for IBFT2 chains using the BONSAI DB format [#7631](https://github.com/hyperledger/besu/pull/7631) ## 24.9.1 diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/RoundTimer.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/RoundTimer.java index 6a8b02991d..a01dc652cf 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/RoundTimer.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/RoundTimer.java @@ -81,7 +81,7 @@ public class RoundTimer { // Once we are up to round 2 start logging round expiries if (round.getRoundNumber() >= 2) { LOG.info( - "QBFT round {} expired. Moved to round {} which will expire in {} seconds", + "BFT round {} expired. Moved to round {} which will expire in {} seconds", round.getRoundNumber() - 1, round.getRoundNumber(), (expiryTime / 1000)); diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/validation/MessageValidator.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/validation/MessageValidator.java index 783861cdfe..1d7b3da9d6 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/validation/MessageValidator.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/validation/MessageValidator.java @@ -78,7 +78,9 @@ public class MessageValidator { return false; } - if (!validateBlock(msg.getBlock())) { + // We want to validate the block but not persist it yet as it's just a proposal. If it turns + // out to be an accepted block it will be persisted at block import time + if (!validateBlockWithoutPersisting(msg.getBlock())) { return false; } @@ -93,14 +95,14 @@ public class MessageValidator { msg.getSignedPayload(), msg.getBlock(), blockInterface); } - private boolean validateBlock(final Block block) { + private boolean validateBlockWithoutPersisting(final Block block) { final BlockValidator blockValidator = protocolSchedule.getByBlockHeader(block.getHeader()).getBlockValidator(); final var validationResult = blockValidator.validateAndProcessBlock( - protocolContext, block, HeaderValidationMode.LIGHT, HeaderValidationMode.FULL); + protocolContext, block, HeaderValidationMode.LIGHT, HeaderValidationMode.FULL, false); if (validationResult.isFailed()) { LOG.info( diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/validation/MessageValidatorTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/validation/MessageValidatorTest.java index f7fb7af3e9..2352642b87 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/validation/MessageValidatorTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/validation/MessageValidatorTest.java @@ -113,7 +113,7 @@ public class MessageValidatorTest { when(protocolSpec.getBlockValidator()).thenReturn(blockValidator); when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec); - when(blockValidator.validateAndProcessBlock(any(), any(), any(), any())) + when(blockValidator.validateAndProcessBlock(any(), any(), any(), any(), eq(false))) .thenReturn(new BlockProcessingResult(Optional.empty())); when(roundChangeCertificateValidator.validateProposalMessageMatchesLatestPrepareCertificate( @@ -168,7 +168,7 @@ public class MessageValidatorTest { @Test public void blockValidationFailureFailsValidation() { - when(blockValidator.validateAndProcessBlock(any(), any(), any(), any())) + when(blockValidator.validateAndProcessBlock(any(), any(), any(), any(), eq(false))) .thenReturn(new BlockProcessingResult("Failed")); final Proposal proposalMsg = From 19d3ca84b282f4db26f95497187209ea7fb6c72d Mon Sep 17 00:00:00 2001 From: Matt Whitehead Date: Fri, 20 Sep 2024 10:12:11 +0100 Subject: [PATCH 03/12] Dev/test option for short BFT block periods (#7588) * Dev mode for short BFT block periods Signed-off-by: Matthew Whitehead * Refactoring Signed-off-by: Matthew Whitehead * Fix comment Signed-off-by: Matthew Whitehead * Refactor to make BFT block milliseconds an experimental QBFT config option Signed-off-by: Matthew Whitehead * Update Json BFT config options Signed-off-by: Matthew Whitehead --------- Signed-off-by: Matthew Whitehead --- .../controller/IbftBesuControllerBuilder.java | 6 +- .../controller/QbftBesuControllerBuilder.java | 6 +- .../besu/config/BftConfigOptions.java | 7 +++ .../org/hyperledger/besu/config/BftFork.java | 13 +++++ .../besu/config/JsonBftConfigOptions.java | 10 ++++ .../besu/consensus/common/bft/BlockTimer.java | 29 ++++++++-- .../common/bft/MutableBftConfigOptions.java | 17 ++++++ .../besu/consensus/common/bft/RoundTimer.java | 12 ++-- .../consensus/common/bft/RoundTimerTest.java | 3 +- .../ibft/support/TestContextBuilder.java | 3 +- ...ftBlockHeaderValidationRulesetFactory.java | 58 +++++++++++-------- .../ibft/IbftProtocolScheduleBuilder.java | 6 +- ...ockHeaderValidationRulesetFactoryTest.java | 6 +- .../blockcreation/BftBlockCreatorTest.java | 5 +- .../qbft/support/TestContextBuilder.java | 3 +- ...ftBlockHeaderValidationRulesetFactory.java | 50 ++++++++++------ .../qbft/QbftForksSchedulesFactory.java | 1 + .../qbft/QbftProtocolScheduleBuilder.java | 5 +- ...ockHeaderValidationRulesetFactoryTest.java | 6 +- 19 files changed, 181 insertions(+), 65 deletions(-) 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 b8d4d2645e..58412029fc 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java @@ -74,6 +74,7 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.plugin.services.BesuEvents; import org.hyperledger.besu.util.Subscribers; +import java.time.Duration; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -182,7 +183,10 @@ public class IbftBesuControllerBuilder extends BftBesuControllerBuilder { Util.publicKeyToAddress(nodeKey.getPublicKey()), proposerSelector, uniqueMessageMulticaster, - new RoundTimer(bftEventQueue, bftConfig.getRequestTimeoutSeconds(), bftExecutors), + new RoundTimer( + bftEventQueue, + Duration.ofSeconds(bftConfig.getRequestTimeoutSeconds()), + bftExecutors), new BlockTimer(bftEventQueue, forksSchedule, bftExecutors, clock), blockCreatorFactory, clock); 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 7961305c48..3d3412d486 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java @@ -84,6 +84,7 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.plugin.services.BesuEvents; import org.hyperledger.besu.util.Subscribers; +import java.time.Duration; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -222,7 +223,10 @@ public class QbftBesuControllerBuilder extends BftBesuControllerBuilder { Util.publicKeyToAddress(nodeKey.getPublicKey()), proposerSelector, uniqueMessageMulticaster, - new RoundTimer(bftEventQueue, qbftConfig.getRequestTimeoutSeconds(), bftExecutors), + new RoundTimer( + bftEventQueue, + Duration.ofSeconds(qbftConfig.getRequestTimeoutSeconds()), + bftExecutors), new BlockTimer(bftEventQueue, qbftForksSchedule, bftExecutors, clock), blockCreatorFactory, clock); diff --git a/config/src/main/java/org/hyperledger/besu/config/BftConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/BftConfigOptions.java index c94752b598..58df7be849 100644 --- a/config/src/main/java/org/hyperledger/besu/config/BftConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/BftConfigOptions.java @@ -37,6 +37,13 @@ public interface BftConfigOptions { */ int getBlockPeriodSeconds(); + /** + * Gets block period milliseconds. For TESTING only. If set then blockperiodseconds is ignored. + * + * @return the block period milliseconds + */ + long getBlockPeriodMilliseconds(); + /** * Gets request timeout seconds. * diff --git a/config/src/main/java/org/hyperledger/besu/config/BftFork.java b/config/src/main/java/org/hyperledger/besu/config/BftFork.java index 30f8e1c5d5..fdaa8f2fa9 100644 --- a/config/src/main/java/org/hyperledger/besu/config/BftFork.java +++ b/config/src/main/java/org/hyperledger/besu/config/BftFork.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Locale; import java.util.Optional; import java.util.OptionalInt; +import java.util.OptionalLong; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.databind.node.ArrayNode; @@ -40,6 +41,9 @@ public class BftFork implements Fork { /** The constant BLOCK_PERIOD_SECONDS_KEY. */ public static final String BLOCK_PERIOD_SECONDS_KEY = "blockperiodseconds"; + /** The constant BLOCK_PERIOD_MILLISECONDS_KEY. */ + public static final String BLOCK_PERIOD_MILLISECONDS_KEY = "xblockperiodmilliseconds"; + /** The constant BLOCK_REWARD_KEY. */ public static final String BLOCK_REWARD_KEY = "blockreward"; @@ -82,6 +86,15 @@ public class BftFork implements Fork { return JsonUtil.getPositiveInt(forkConfigRoot, BLOCK_PERIOD_SECONDS_KEY); } + /** + * Gets block period milliseconds. Experimental for test scenarios only. + * + * @return the block period milliseconds + */ + public OptionalLong getBlockPeriodMilliseconds() { + return JsonUtil.getLong(forkConfigRoot, BLOCK_PERIOD_MILLISECONDS_KEY); + } + /** * Gets block reward wei. * diff --git a/config/src/main/java/org/hyperledger/besu/config/JsonBftConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/JsonBftConfigOptions.java index 95f2d9f7ce..b1c8630b39 100644 --- a/config/src/main/java/org/hyperledger/besu/config/JsonBftConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/JsonBftConfigOptions.java @@ -34,6 +34,7 @@ public class JsonBftConfigOptions implements BftConfigOptions { private static final long DEFAULT_EPOCH_LENGTH = 30_000; private static final int DEFAULT_BLOCK_PERIOD_SECONDS = 1; + private static final int DEFAULT_BLOCK_PERIOD_MILLISECONDS = 0; // Experimental for test only private static final int DEFAULT_ROUND_EXPIRY_SECONDS = 1; // In a healthy network this can be very small. This default limit will allow for suitable // protection for on a typical 20 node validator network with multiple rounds @@ -66,6 +67,12 @@ public class JsonBftConfigOptions implements BftConfigOptions { bftConfigRoot, "blockperiodseconds", DEFAULT_BLOCK_PERIOD_SECONDS); } + @Override + public long getBlockPeriodMilliseconds() { + return JsonUtil.getLong( + bftConfigRoot, "xblockperiodmilliseconds", DEFAULT_BLOCK_PERIOD_MILLISECONDS); + } + @Override public int getRequestTimeoutSeconds() { return JsonUtil.getInt(bftConfigRoot, "requesttimeoutseconds", DEFAULT_ROUND_EXPIRY_SECONDS); @@ -133,6 +140,9 @@ public class JsonBftConfigOptions implements BftConfigOptions { if (bftConfigRoot.has("blockperiodseconds")) { builder.put("blockPeriodSeconds", getBlockPeriodSeconds()); } + if (bftConfigRoot.has("xblockperiodmilliseconds")) { + builder.put("xBlockPeriodMilliSeconds", getBlockPeriodMilliseconds()); + } if (bftConfigRoot.has("requesttimeoutseconds")) { builder.put("requestTimeoutSeconds", getRequestTimeoutSeconds()); } diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BlockTimer.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BlockTimer.java index 5649b69e8f..49ef94e008 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BlockTimer.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BlockTimer.java @@ -24,9 +24,14 @@ import java.util.Optional; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** Class for starting and keeping organised block timers */ public class BlockTimer { + private static final Logger LOG = LoggerFactory.getLogger(BlockTimer.class); + private final ForksSchedule forksSchedule; private final BftExecutors bftExecutors; private Optional> currentTimerTask; @@ -79,12 +84,26 @@ public class BlockTimer { cancelTimer(); final long now = clock.millis(); + final long expiryTime; + + // Experimental option for test scenarios only. Not for production use. + final long blockPeriodMilliseconds = + forksSchedule.getFork(round.getSequenceNumber()).getValue().getBlockPeriodMilliseconds(); - // absolute time when the timer is supposed to expire - final int blockPeriodSeconds = - forksSchedule.getFork(round.getSequenceNumber()).getValue().getBlockPeriodSeconds(); - final long minimumTimeBetweenBlocksMillis = blockPeriodSeconds * 1000L; - final long expiryTime = chainHeadHeader.getTimestamp() * 1_000 + minimumTimeBetweenBlocksMillis; + if (blockPeriodMilliseconds > 0) { + // Experimental mode for setting < 1 second block periods e.g. for CI/CD pipelines + // running tests against Besu + expiryTime = clock.millis() + blockPeriodMilliseconds; + LOG.warn( + "Test-mode only xblockperiodmilliseconds has been set to {} millisecond blocks. Do not use in a production system.", + blockPeriodMilliseconds); + } else { + // absolute time when the timer is supposed to expire + final int blockPeriodSeconds = + forksSchedule.getFork(round.getSequenceNumber()).getValue().getBlockPeriodSeconds(); + final long minimumTimeBetweenBlocksMillis = blockPeriodSeconds * 1000L; + expiryTime = chainHeadHeader.getTimestamp() * 1_000 + minimumTimeBetweenBlocksMillis; + } if (expiryTime > now) { final long delay = expiryTime - now; diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/MutableBftConfigOptions.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/MutableBftConfigOptions.java index fd406ea5e1..7b27c7b4c4 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/MutableBftConfigOptions.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/MutableBftConfigOptions.java @@ -31,6 +31,7 @@ import java.util.Optional; public class MutableBftConfigOptions implements BftConfigOptions { private long epochLength; private int blockPeriodSeconds; + private long blockPeriodMilliseconds; private int requestTimeoutSeconds; private int gossipedHistoryLimit; private int messageQueueLimit; @@ -48,6 +49,7 @@ public class MutableBftConfigOptions implements BftConfigOptions { public MutableBftConfigOptions(final BftConfigOptions bftConfigOptions) { this.epochLength = bftConfigOptions.getEpochLength(); this.blockPeriodSeconds = bftConfigOptions.getBlockPeriodSeconds(); + this.blockPeriodMilliseconds = bftConfigOptions.getBlockPeriodMilliseconds(); this.requestTimeoutSeconds = bftConfigOptions.getRequestTimeoutSeconds(); this.gossipedHistoryLimit = bftConfigOptions.getGossipedHistoryLimit(); this.messageQueueLimit = bftConfigOptions.getMessageQueueLimit(); @@ -68,6 +70,11 @@ public class MutableBftConfigOptions implements BftConfigOptions { return blockPeriodSeconds; } + @Override + public long getBlockPeriodMilliseconds() { + return blockPeriodMilliseconds; + } + @Override public int getRequestTimeoutSeconds() { return requestTimeoutSeconds; @@ -131,6 +138,16 @@ public class MutableBftConfigOptions implements BftConfigOptions { this.blockPeriodSeconds = blockPeriodSeconds; } + /** + * Sets block period milliseconds. Experimental for test scenarios. Not for use on production + * systems. + * + * @param blockPeriodMilliseconds the block period milliseconds + */ + public void setBlockPeriodMilliseconds(final long blockPeriodMilliseconds) { + this.blockPeriodMilliseconds = blockPeriodMilliseconds; + } + /** * Sets request timeout seconds. * diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/RoundTimer.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/RoundTimer.java index a01dc652cf..0302943fc1 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/RoundTimer.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/RoundTimer.java @@ -16,6 +16,7 @@ package org.hyperledger.besu.consensus.common.bft; import org.hyperledger.besu.consensus.common.bft.events.RoundExpiry; +import java.time.Duration; import java.util.Optional; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -31,21 +32,21 @@ public class RoundTimer { private final BftExecutors bftExecutors; private Optional> currentTimerTask; private final BftEventQueue queue; - private final long baseExpiryMillis; + private final Duration baseExpiryPeriod; /** * Construct a RoundTimer with primed executor service ready to start timers * * @param queue The queue in which to put round expiry events - * @param baseExpirySeconds The initial round length for round 0 + * @param baseExpiryPeriod The initial round length for round 0 * @param bftExecutors executor service that timers can be scheduled with */ public RoundTimer( - final BftEventQueue queue, final long baseExpirySeconds, final BftExecutors bftExecutors) { + final BftEventQueue queue, final Duration baseExpiryPeriod, final BftExecutors bftExecutors) { this.queue = queue; this.bftExecutors = bftExecutors; this.currentTimerTask = Optional.empty(); - this.baseExpiryMillis = baseExpirySeconds * 1000; + this.baseExpiryPeriod = baseExpiryPeriod; } /** Cancels the current running round timer if there is one */ @@ -71,7 +72,8 @@ public class RoundTimer { public synchronized void startTimer(final ConsensusRoundIdentifier round) { cancelTimer(); - final long expiryTime = baseExpiryMillis * (long) Math.pow(2, round.getRoundNumber()); + final long expiryTime = + baseExpiryPeriod.toMillis() * (long) Math.pow(2, round.getRoundNumber()); final Runnable newTimerRunnable = () -> queue.add(new RoundExpiry(round)); diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/RoundTimerTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/RoundTimerTest.java index 0ebca51c9e..8f43739547 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/RoundTimerTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/RoundTimerTest.java @@ -25,6 +25,7 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.consensus.common.bft.events.RoundExpiry; +import java.time.Duration; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -46,7 +47,7 @@ public class RoundTimerTest { bftExecutors = mock(BftExecutors.class); queue = new BftEventQueue(1000); queue.start(); - timer = new RoundTimer(queue, 1, bftExecutors); + timer = new RoundTimer(queue, Duration.ofSeconds(1), bftExecutors); } @Test diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java index 5d2b02b1a7..8896733548 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java @@ -100,6 +100,7 @@ import org.hyperledger.besu.testutil.TestClock; import org.hyperledger.besu.util.Subscribers; import java.time.Clock; +import java.time.Duration; import java.time.Instant; import java.time.ZoneId; import java.util.ArrayList; @@ -403,7 +404,7 @@ public class TestContextBuilder { Util.publicKeyToAddress(nodeKey.getPublicKey()), proposerSelector, multicaster, - new RoundTimer(bftEventQueue, ROUND_TIMER_SEC, bftExecutors), + new RoundTimer(bftEventQueue, Duration.ofSeconds(ROUND_TIMER_SEC), bftExecutors), new BlockTimer(bftEventQueue, forksSchedule, bftExecutors, TestClock.fixed()), blockCreatorFactory, clock); diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftBlockHeaderValidationRulesetFactory.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftBlockHeaderValidationRulesetFactory.java index 0e71fe8121..2367f90e2b 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftBlockHeaderValidationRulesetFactory.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftBlockHeaderValidationRulesetFactory.java @@ -32,6 +32,7 @@ import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.GasUsageValid import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.TimestampBoundedByFutureParameter; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.TimestampMoreRecentThanParent; +import java.time.Duration; import java.util.Optional; import org.apache.tuweni.units.bigints.UInt256; @@ -45,32 +46,43 @@ public class IbftBlockHeaderValidationRulesetFactory { * Produces a BlockHeaderValidator configured for assessing bft block headers which are to form * part of the BlockChain (i.e. not proposed blocks, which do not contain commit seals) * - * @param secondsBetweenBlocks the minimum number of seconds which must elapse between blocks. + * @param minimumTimeBetweenBlocks the minimum time which must elapse between blocks. * @param baseFeeMarket an {@link Optional} wrapping {@link BaseFeeMarket} class if appropriate. * @return BlockHeaderValidator configured for assessing bft block headers */ public static BlockHeaderValidator.Builder blockHeaderValidator( - final long secondsBetweenBlocks, final Optional baseFeeMarket) { - return new BlockHeaderValidator.Builder() - .addRule(new AncestryValidationRule()) - .addRule(new GasUsageValidationRule()) - .addRule( - new GasLimitRangeAndDeltaValidationRule( - DEFAULT_MIN_GAS_LIMIT, DEFAULT_MAX_GAS_LIMIT, baseFeeMarket)) - .addRule(new TimestampBoundedByFutureParameter(1)) - .addRule(new TimestampMoreRecentThanParent(secondsBetweenBlocks)) - .addRule( - new ConstantFieldValidationRule<>( - "MixHash", BlockHeader::getMixHash, BftHelpers.EXPECTED_MIX_HASH)) - .addRule( - new ConstantFieldValidationRule<>( - "OmmersHash", BlockHeader::getOmmersHash, Hash.EMPTY_LIST_HASH)) - .addRule( - new ConstantFieldValidationRule<>( - "Difficulty", BlockHeader::getDifficulty, UInt256.ONE)) - .addRule(new ConstantFieldValidationRule<>("Nonce", BlockHeader::getNonce, 0L)) - .addRule(new BftValidatorsValidationRule()) - .addRule(new BftCoinbaseValidationRule()) - .addRule(new BftCommitSealsValidationRule()); + final Duration minimumTimeBetweenBlocks, final Optional baseFeeMarket) { + final BlockHeaderValidator.Builder ruleBuilder = + new BlockHeaderValidator.Builder() + .addRule(new AncestryValidationRule()) + .addRule(new GasUsageValidationRule()) + .addRule( + new GasLimitRangeAndDeltaValidationRule( + DEFAULT_MIN_GAS_LIMIT, DEFAULT_MAX_GAS_LIMIT, baseFeeMarket)) + .addRule(new TimestampBoundedByFutureParameter(1)) + .addRule( + new ConstantFieldValidationRule<>( + "MixHash", BlockHeader::getMixHash, BftHelpers.EXPECTED_MIX_HASH)) + .addRule( + new ConstantFieldValidationRule<>( + "OmmersHash", BlockHeader::getOmmersHash, Hash.EMPTY_LIST_HASH)) + .addRule( + new ConstantFieldValidationRule<>( + "Difficulty", BlockHeader::getDifficulty, UInt256.ONE)) + .addRule(new ConstantFieldValidationRule<>("Nonce", BlockHeader::getNonce, 0L)) + .addRule(new BftValidatorsValidationRule()) + .addRule(new BftCoinbaseValidationRule()) + .addRule(new BftCommitSealsValidationRule()); + + // Currently the minimum acceptable time between blocks is 1 second. The timestamp of an + // Ethereum header is stored as seconds since Unix epoch so blocks being produced more + // frequently than once a second cannot pass this validator. For non-production scenarios + // (e.g. for testing block production much more frequently than once a second) Besu has + // an experimental 'xblockperiodmilliseconds' option for BFT chains. If this is enabled + // we cannot apply the TimestampMoreRecentThanParent validation rule so we do not add it + if (minimumTimeBetweenBlocks.compareTo(Duration.ofSeconds(1)) >= 0) { + ruleBuilder.addRule(new TimestampMoreRecentThanParent(minimumTimeBetweenBlocks.getSeconds())); + } + return ruleBuilder; } } diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleBuilder.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleBuilder.java index 0789f2e898..3adf571895 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleBuilder.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleBuilder.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.plugin.services.MetricsSystem; +import java.time.Duration; import java.util.Optional; /** Defines the protocol behaviours for a blockchain using a BFT consensus mechanism. */ @@ -120,6 +121,9 @@ public class IbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder Optional.of(feeMarket).filter(FeeMarket::implementsBaseFee).map(BaseFeeMarket.class::cast); return IbftBlockHeaderValidationRulesetFactory.blockHeaderValidator( - config.getBlockPeriodSeconds(), baseFeeMarket); + config.getBlockPeriodMilliseconds() > 0 + ? Duration.ofMillis(config.getBlockPeriodMilliseconds()) + : Duration.ofSeconds(config.getBlockPeriodSeconds()), + baseFeeMarket); } } diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftBlockHeaderValidationRulesetFactoryTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftBlockHeaderValidationRulesetFactoryTest.java index a7deb9e197..160fc2a2f3 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftBlockHeaderValidationRulesetFactoryTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftBlockHeaderValidationRulesetFactoryTest.java @@ -38,6 +38,7 @@ import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; +import java.time.Duration; import java.util.Collection; import java.util.List; import java.util.Optional; @@ -93,7 +94,7 @@ public class IbftBlockHeaderValidationRulesetFactoryTest { final BlockHeaderValidator validator = IbftBlockHeaderValidationRulesetFactory.blockHeaderValidator( - 5, Optional.of(FeeMarket.london(1))) + Duration.ofSeconds(5), Optional.of(FeeMarket.london(1))) .build(); assertThat( @@ -372,7 +373,8 @@ public class IbftBlockHeaderValidationRulesetFactoryTest { } public BlockHeaderValidator getBlockHeaderValidator() { - return IbftBlockHeaderValidationRulesetFactory.blockHeaderValidator(5, Optional.empty()) + return IbftBlockHeaderValidationRulesetFactory.blockHeaderValidator( + Duration.ofSeconds(5), Optional.empty()) .build(); } } diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java index 8b8406b638..5469717b13 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java @@ -64,6 +64,7 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.testutil.DeterministicEthScheduler; import org.hyperledger.besu.testutil.TestClock; +import java.time.Duration; import java.time.ZoneId; import java.util.Collections; import java.util.List; @@ -105,7 +106,7 @@ public class BftBlockCreatorTest { public BlockHeaderValidator.Builder createBlockHeaderRuleset( final BftConfigOptions config, final FeeMarket feeMarket) { return IbftBlockHeaderValidationRulesetFactory.blockHeaderValidator( - 5, Optional.empty()); + Duration.ofSeconds(5), Optional.empty()); } }; final GenesisConfigOptions configOptions = @@ -200,7 +201,7 @@ public class BftBlockCreatorTest { final BlockHeaderValidator rules = IbftBlockHeaderValidationRulesetFactory.blockHeaderValidator( - secondsBetweenBlocks, Optional.empty()) + Duration.ofSeconds(secondsBetweenBlocks), Optional.empty()) .build(); // NOTE: The header will not contain commit seals, so can only do light validation on header. diff --git a/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java b/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java index 8906f0de7f..d90d5a1527 100644 --- a/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java +++ b/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java @@ -118,6 +118,7 @@ import org.hyperledger.besu.util.Subscribers; import java.io.IOException; import java.nio.file.Path; import java.time.Clock; +import java.time.Duration; import java.time.Instant; import java.time.ZoneId; import java.util.ArrayList; @@ -512,7 +513,7 @@ public class TestContextBuilder { Util.publicKeyToAddress(nodeKey.getPublicKey()), proposerSelector, multicaster, - new RoundTimer(bftEventQueue, ROUND_TIMER_SEC, bftExecutors), + new RoundTimer(bftEventQueue, Duration.ofSeconds(ROUND_TIMER_SEC), bftExecutors), new BlockTimer(bftEventQueue, forksSchedule, bftExecutors, TestClock.fixed()), blockCreatorFactory, clock); diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactory.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactory.java index 7320dfaaf7..ac5ba3ac23 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactory.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactory.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.GasUsageValid import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.TimestampBoundedByFutureParameter; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.TimestampMoreRecentThanParent; +import java.time.Duration; import java.util.Optional; import org.apache.tuweni.units.bigints.UInt256; @@ -44,31 +45,42 @@ public class QbftBlockHeaderValidationRulesetFactory { * Produces a BlockHeaderValidator configured for assessing bft block headers which are to form * part of the BlockChain (i.e. not proposed blocks, which do not contain commit seals) * - * @param secondsBetweenBlocks the minimum number of seconds which must elapse between blocks. + * @param minimumTimeBetweenBlocks the minimum amount of time that must elapse between blocks. * @param useValidatorContract whether validator selection is using a validator contract * @param baseFeeMarket an {@link Optional} wrapping {@link BaseFeeMarket} class if appropriate. * @return BlockHeaderValidator configured for assessing bft block headers */ public static BlockHeaderValidator.Builder blockHeaderValidator( - final long secondsBetweenBlocks, + final Duration minimumTimeBetweenBlocks, final boolean useValidatorContract, final Optional baseFeeMarket) { - return new BlockHeaderValidator.Builder() - .addRule(new AncestryValidationRule()) - .addRule(new GasUsageValidationRule()) - .addRule( - new GasLimitRangeAndDeltaValidationRule( - DEFAULT_MIN_GAS_LIMIT, DEFAULT_MAX_GAS_LIMIT, baseFeeMarket)) - .addRule(new TimestampBoundedByFutureParameter(1)) - .addRule(new TimestampMoreRecentThanParent(secondsBetweenBlocks)) - .addRule( - new ConstantFieldValidationRule<>( - "MixHash", BlockHeader::getMixHash, BftHelpers.EXPECTED_MIX_HASH)) - .addRule( - new ConstantFieldValidationRule<>( - "Difficulty", BlockHeader::getDifficulty, UInt256.ONE)) - .addRule(new QbftValidatorsValidationRule(useValidatorContract)) - .addRule(new BftCoinbaseValidationRule()) - .addRule(new BftCommitSealsValidationRule()); + BlockHeaderValidator.Builder ruleBuilder = + new BlockHeaderValidator.Builder() + .addRule(new AncestryValidationRule()) + .addRule(new GasUsageValidationRule()) + .addRule( + new GasLimitRangeAndDeltaValidationRule( + DEFAULT_MIN_GAS_LIMIT, DEFAULT_MAX_GAS_LIMIT, baseFeeMarket)) + .addRule(new TimestampBoundedByFutureParameter(1)) + .addRule( + new ConstantFieldValidationRule<>( + "MixHash", BlockHeader::getMixHash, BftHelpers.EXPECTED_MIX_HASH)) + .addRule( + new ConstantFieldValidationRule<>( + "Difficulty", BlockHeader::getDifficulty, UInt256.ONE)) + .addRule(new QbftValidatorsValidationRule(useValidatorContract)) + .addRule(new BftCoinbaseValidationRule()) + .addRule(new BftCommitSealsValidationRule()); + + // Currently the minimum acceptable time between blocks is 1 second. The timestamp of an + // Ethereum header is stored as seconds since Unix epoch so blocks being produced more + // frequently than once a second cannot pass this validator. For non-production scenarios + // (e.g. for testing block production much more frequently than once a second) Besu has + // an experimental 'xblockperiodmilliseconds' option for BFT chains. If this is enabled + // we cannot apply the TimestampMoreRecentThanParent validation rule so we do not add it + if (minimumTimeBetweenBlocks.compareTo(Duration.ofSeconds(1)) >= 0) { + ruleBuilder.addRule(new TimestampMoreRecentThanParent(minimumTimeBetweenBlocks.getSeconds())); + } + return ruleBuilder; } } diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftForksSchedulesFactory.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftForksSchedulesFactory.java index 90448f6201..0f0d467de3 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftForksSchedulesFactory.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftForksSchedulesFactory.java @@ -49,6 +49,7 @@ public class QbftForksSchedulesFactory { new MutableQbftConfigOptions(lastSpec.getValue()); fork.getBlockPeriodSeconds().ifPresent(bftConfigOptions::setBlockPeriodSeconds); + fork.getBlockPeriodMilliseconds().ifPresent(bftConfigOptions::setBlockPeriodMilliseconds); fork.getBlockRewardWei().ifPresent(bftConfigOptions::setBlockRewardWei); if (fork.isMiningBeneficiaryConfigured()) { diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleBuilder.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleBuilder.java index 44c7ddfba8..e1cbc134b6 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleBuilder.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleBuilder.java @@ -33,6 +33,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.plugin.services.MetricsSystem; +import java.time.Duration; import java.util.Optional; /** Defines the protocol behaviours for a blockchain using a QBFT consensus mechanism. */ @@ -164,7 +165,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder Optional.of(feeMarket).filter(FeeMarket::implementsBaseFee).map(BaseFeeMarket.class::cast); return QbftBlockHeaderValidationRulesetFactory.blockHeaderValidator( - qbftConfigOptions.getBlockPeriodSeconds(), + qbftConfigOptions.getBlockPeriodMilliseconds() > 0 + ? Duration.ofMillis(qbftConfigOptions.getBlockPeriodMilliseconds()) + : Duration.ofSeconds(qbftConfigOptions.getBlockPeriodSeconds()), qbftConfigOptions.isValidatorContractMode(), baseFeeMarket); } diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactoryTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactoryTest.java index 4771cf91cb..ae1fbc0f19 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactoryTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactoryTest.java @@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; +import java.time.Duration; import java.util.Collection; import java.util.List; import java.util.Optional; @@ -92,7 +93,7 @@ public class QbftBlockHeaderValidationRulesetFactoryTest { final BlockHeaderValidator validator = QbftBlockHeaderValidationRulesetFactory.blockHeaderValidator( - 5, false, Optional.of(FeeMarket.london(1))) + Duration.ofSeconds(5), false, Optional.of(FeeMarket.london(1))) .build(); assertThat( @@ -366,7 +367,8 @@ public class QbftBlockHeaderValidationRulesetFactoryTest { } public BlockHeaderValidator getBlockHeaderValidator() { - return QbftBlockHeaderValidationRulesetFactory.blockHeaderValidator(5, false, Optional.empty()) + return QbftBlockHeaderValidationRulesetFactory.blockHeaderValidator( + Duration.ofSeconds(5), false, Optional.empty()) .build(); } } From 3dbe60617249446222fa786e9bb82ea3311a361a Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 20 Sep 2024 15:10:59 +0200 Subject: [PATCH 04/12] Wait for Besu to be up before running Goss Docker test 02 (#7655) Signed-off-by: Fabio Di Fabio --- docker/tests/02/goss_wait.yaml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 docker/tests/02/goss_wait.yaml diff --git a/docker/tests/02/goss_wait.yaml b/docker/tests/02/goss_wait.yaml new file mode 100644 index 0000000000..f6b397c618 --- /dev/null +++ b/docker/tests/02/goss_wait.yaml @@ -0,0 +1,7 @@ +--- +# runtime docker tests for interfaces & ports +port: + tcp:30303: + listening: true + ip: + - 0.0.0.0 From 676e1f8c1344edd3009eba6f22a46287b4e98bdb Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 20 Sep 2024 15:52:12 +0200 Subject: [PATCH 05/12] Rebalance GHA runners to reduce ATs failure and speedup unit tests (#7656) Signed-off-by: Fabio Di Fabio --- .github/workflows/acceptance-tests.yml | 2 +- .github/workflows/pre-review.yml | 2 +- .github/workflows/reference-tests.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index a8f6981d89..27d0020b2c 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -12,7 +12,7 @@ concurrency: env: GRADLE_OPTS: "-Xmx7g" - total-runners: 12 + total-runners: 14 jobs: acceptanceTestEthereum: diff --git a/.github/workflows/pre-review.yml b/.github/workflows/pre-review.yml index cba13f1ebd..35e8956f1d 100644 --- a/.github/workflows/pre-review.yml +++ b/.github/workflows/pre-review.yml @@ -12,7 +12,7 @@ concurrency: env: GRADLE_OPTS: "-Xmx6g -Dorg.gradle.parallel=true" - total-runners: 8 + total-runners: 10 jobs: repolint: diff --git a/.github/workflows/reference-tests.yml b/.github/workflows/reference-tests.yml index 4e458e057e..435cbba0f8 100644 --- a/.github/workflows/reference-tests.yml +++ b/.github/workflows/reference-tests.yml @@ -8,7 +8,7 @@ on: env: GRADLE_OPTS: "-Xmx6g -Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.caching=true" - total-runners: 10 + total-runners: 8 concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} From f1da4e77e6fc7bd9eefc61b0f82d367962debb1b Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 20 Sep 2024 16:31:37 +0200 Subject: [PATCH 06/12] Rebalance GHA runners to reduce ATs failure and speedup unit tests [part 2] (#7658) Signed-off-by: Fabio Di Fabio --- .github/workflows/acceptance-tests.yml | 2 +- .github/workflows/pre-review.yml | 2 +- .github/workflows/reference-tests.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 27d0020b2c..e1549b2357 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -24,7 +24,7 @@ jobs: strategy: fail-fast: true matrix: - runner_index: [0,1,2,3,4,5,6,7,8,9,10,11] + runner_index: [0,1,2,3,4,5,6,7,8,9,10,11,12,13] steps: - name: Checkout Repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 diff --git a/.github/workflows/pre-review.yml b/.github/workflows/pre-review.yml index 35e8956f1d..93bfcfa9f5 100644 --- a/.github/workflows/pre-review.yml +++ b/.github/workflows/pre-review.yml @@ -83,7 +83,7 @@ jobs: strategy: fail-fast: true matrix: - runner_index: [0,1,2,3,4,5,6,7] + runner_index: [0,1,2,3,4,5,6,7,8,9] steps: - name: Checkout Repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 diff --git a/.github/workflows/reference-tests.yml b/.github/workflows/reference-tests.yml index 435cbba0f8..d27114ebc1 100644 --- a/.github/workflows/reference-tests.yml +++ b/.github/workflows/reference-tests.yml @@ -24,7 +24,7 @@ jobs: strategy: fail-fast: true matrix: - runner_index: [1,2,3,4,5,6,7,8,9,10] + runner_index: [1,2,3,4,5,6,7,8] steps: - name: Checkout Repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 From 3e0e5cdc1ffa0888ebba96e0edb3a9bdf18eb17e Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 20 Sep 2024 17:11:56 +0200 Subject: [PATCH 07/12] Fix reading tx-pool-min-score option from configuration file (#7623) Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../util/TomlConfigurationDefaultProvider.java | 6 +++++- .../options/TransactionPoolOptionsTest.java | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 246df1d91c..96e1511eea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Fix for `debug_traceCall` to handle transactions without specified gas price. [#7510](https://github.com/hyperledger/besu/pull/7510) - Corrects a regression where custom plugin services are not initialized correctly. [#7625](https://github.com/hyperledger/besu/pull/7625) - Fix for IBFT2 chains using the BONSAI DB format [#7631](https://github.com/hyperledger/besu/pull/7631) +- Fix reading `tx-pool-min-score` option from configuration file [#7623](https://github.com/hyperledger/besu/pull/7623) ## 24.9.1 diff --git a/besu/src/main/java/org/hyperledger/besu/cli/util/TomlConfigurationDefaultProvider.java b/besu/src/main/java/org/hyperledger/besu/cli/util/TomlConfigurationDefaultProvider.java index ca76b40b68..636be329d4 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/util/TomlConfigurationDefaultProvider.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/util/TomlConfigurationDefaultProvider.java @@ -120,7 +120,11 @@ public class TomlConfigurationDefaultProvider implements IDefaultValueProvider { } private boolean isNumericType(final Class type) { - return type.equals(Integer.class) + return type.equals(Byte.class) + || type.equals(byte.class) + || type.equals(Short.class) + || type.equals(short.class) + || type.equals(Integer.class) || type.equals(int.class) || type.equals(Long.class) || type.equals(long.class) diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java index eb48a3f2a5..37acbe167f 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java @@ -427,6 +427,24 @@ public class TransactionPoolOptionsTest Byte.toString(minScore)); } + @Test + public void minScoreWorksConfigFile() throws IOException { + final byte minScore = -10; + final Path tempConfigFilePath = + createTempFile( + "config", + String.format( + """ + tx-pool-min-score=%s + """, + minScore)); + + internalTestSuccess( + config -> assertThat(config.getMinScore()).isEqualTo(minScore), + "--config-file", + tempConfigFilePath.toString()); + } + @Test public void minScoreNonByteValueReturnError() { final var overflowMinScore = Integer.toString(-300); From 6e246ca4b0be04fe14f67a25cde895c127feeec4 Mon Sep 17 00:00:00 2001 From: Cooper Mosawi Date: Sat, 21 Sep 2024 05:13:16 +1200 Subject: [PATCH 08/12] fix opentelemetry (#7649) Signed-off-by: Blue Co-authored-by: Fabio Di Fabio --- docs/tracing/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tracing/README.md b/docs/tracing/README.md index 77deadd16a..3a3f9fa435 100644 --- a/docs/tracing/README.md +++ b/docs/tracing/README.md @@ -1,6 +1,6 @@ # Tracing -Hyperledger Besu integrates with the [open-telemetry](https://open-telemetry.io) project to integrate tracing reporting. +Hyperledger Besu integrates with the [open-telemetry](https://opentelemetry.io/) project to integrate tracing reporting. This allows to report all JSON-RPC traffic as traces. From 1751a77f98cc6cdf218cd80f429e15ccd8e01e67 Mon Sep 17 00:00:00 2001 From: daniellehrner Date: Sat, 21 Sep 2024 13:28:01 +0200 Subject: [PATCH 09/12] 7702 validation checks v2 (#7653) * yParity is valid up to 2**256 as well Signed-off-by: Daniel Lehrner --- .../besu/crypto/AbstractSECP256.java | 2 +- .../besu/crypto/CodeDelegationSignature.java | 15 ++++++++--- .../besu/crypto/SignatureAlgorithm.java | 2 +- .../crypto/CodeDelegationSignatureTest.java | 27 +++++++++++++------ .../CodeDelegationTransactionDecoder.java | 2 +- 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/AbstractSECP256.java b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/AbstractSECP256.java index ce37651266..bd450b206e 100644 --- a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/AbstractSECP256.java +++ b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/AbstractSECP256.java @@ -214,7 +214,7 @@ public abstract class AbstractSECP256 implements SignatureAlgorithm { @Override public CodeDelegationSignature createCodeDelegationSignature( - final BigInteger r, final BigInteger s, final long yParity) { + final BigInteger r, final BigInteger s, final BigInteger yParity) { return CodeDelegationSignature.create(r, s, yParity); } diff --git a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/CodeDelegationSignature.java b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/CodeDelegationSignature.java index 4bb2e4653e..06ec72bf0a 100644 --- a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/CodeDelegationSignature.java +++ b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/CodeDelegationSignature.java @@ -42,18 +42,25 @@ public class CodeDelegationSignature extends SECPSignature { * @return the new CodeDelegationSignature */ public static CodeDelegationSignature create( - final BigInteger r, final BigInteger s, final long yParity) { + final BigInteger r, final BigInteger s, final BigInteger yParity) { checkNotNull(r); checkNotNull(s); if (r.compareTo(TWO_POW_256) >= 0) { - throw new IllegalArgumentException("Invalid 'r' value, should be < 2^256 but got " + r); + throw new IllegalArgumentException( + "Invalid 'r' value, should be < 2^256 but got " + r.toString(16)); } if (s.compareTo(TWO_POW_256) >= 0) { - throw new IllegalArgumentException("Invalid 's' value, should be < 2^256 but got " + s); + throw new IllegalArgumentException( + "Invalid 's' value, should be < 2^256 but got " + s.toString(16)); } - return new CodeDelegationSignature(r, s, (byte) yParity); + if (yParity.compareTo(TWO_POW_256) >= 0) { + throw new IllegalArgumentException( + "Invalid 'yParity' value, should be < 2^256 but got " + yParity.toString(16)); + } + + return new CodeDelegationSignature(r, s, yParity.byteValue()); } } diff --git a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/SignatureAlgorithm.java b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/SignatureAlgorithm.java index 8e19b60854..4bf8d89c82 100644 --- a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/SignatureAlgorithm.java +++ b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/SignatureAlgorithm.java @@ -224,7 +224,7 @@ public interface SignatureAlgorithm { * @return the code delegation signature */ CodeDelegationSignature createCodeDelegationSignature( - final BigInteger r, final BigInteger s, final long yParity); + final BigInteger r, final BigInteger s, final BigInteger yParity); /** * Decode secp signature. diff --git a/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/CodeDelegationSignatureTest.java b/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/CodeDelegationSignatureTest.java index 1cc66966a7..332aa14893 100644 --- a/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/CodeDelegationSignatureTest.java +++ b/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/CodeDelegationSignatureTest.java @@ -29,19 +29,19 @@ class CodeDelegationSignatureTest { void testValidInputs() { BigInteger r = BigInteger.ONE; BigInteger s = BigInteger.TEN; - long yParity = 1L; + BigInteger yParity = BigInteger.ONE; CodeDelegationSignature result = CodeDelegationSignature.create(r, s, yParity); assertThat(r).isEqualTo(result.getR()); assertThat(s).isEqualTo(result.getS()); - assertThat((byte) yParity).isEqualTo(result.getRecId()); + assertThat(yParity.byteValue()).isEqualTo(result.getRecId()); } @Test void testNullRValue() { BigInteger s = BigInteger.TEN; - long yParity = 0L; + BigInteger yParity = BigInteger.ZERO; assertThatExceptionOfType(NullPointerException.class) .isThrownBy(() -> CodeDelegationSignature.create(null, s, yParity)); @@ -50,7 +50,7 @@ class CodeDelegationSignatureTest { @Test void testNullSValue() { BigInteger r = BigInteger.ONE; - long yParity = 0L; + BigInteger yParity = BigInteger.ZERO; assertThatExceptionOfType(NullPointerException.class) .isThrownBy(() -> CodeDelegationSignature.create(r, null, yParity)); @@ -60,7 +60,7 @@ class CodeDelegationSignatureTest { void testRValueExceedsTwoPow256() { BigInteger r = TWO_POW_256; BigInteger s = BigInteger.TEN; - long yParity = 0L; + BigInteger yParity = BigInteger.ZERO; assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(() -> CodeDelegationSignature.create(r, s, yParity)) @@ -71,23 +71,34 @@ class CodeDelegationSignatureTest { void testSValueExceedsTwoPow256() { BigInteger r = BigInteger.ONE; BigInteger s = TWO_POW_256; - long yParity = 0L; + BigInteger yParity = BigInteger.ZERO; assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(() -> CodeDelegationSignature.create(r, s, yParity)) .withMessageContainingAll("Invalid 's' value, should be < 2^256"); } + @Test + void testYParityExceedsTwoPow256() { + BigInteger r = BigInteger.ONE; + BigInteger s = BigInteger.TWO; + BigInteger yParity = TWO_POW_256; + + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> CodeDelegationSignature.create(r, s, yParity)) + .withMessageContainingAll("Invalid 'yParity' value, should be < 2^256"); + } + @Test void testValidYParityZero() { BigInteger r = BigInteger.ONE; BigInteger s = BigInteger.TEN; - long yParity = 0L; + BigInteger yParity = BigInteger.ZERO; CodeDelegationSignature result = CodeDelegationSignature.create(r, s, yParity); assertThat(r).isEqualTo(result.getR()); assertThat(s).isEqualTo(result.getS()); - assertThat((byte) yParity).isEqualTo(result.getRecId()); + assertThat(yParity.byteValue()).isEqualTo(result.getRecId()); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionDecoder.java index d3ef60bfc4..6448940d8d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionDecoder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionDecoder.java @@ -81,7 +81,7 @@ public class CodeDelegationTransactionDecoder { final Address address = Address.wrap(input.readBytes()); final long nonce = input.readLongScalar(); - final long yParity = input.readUnsignedIntScalar(); + final BigInteger yParity = input.readUInt256Scalar().toUnsignedBigInteger(); final BigInteger r = input.readUInt256Scalar().toUnsignedBigInteger(); final BigInteger s = input.readUInt256Scalar().toUnsignedBigInteger(); From 9d689b940134b4f7a9b80020829d506417c2065e Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Sun, 22 Sep 2024 06:45:09 +1000 Subject: [PATCH 10/12] remove integration tests related to privacy (#7645) * remove integration tests related to privacy Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane --- .../hyperledger/besu/enclave/EnclaveTest.java | 215 --------------- .../enclave/TlsCertificateDefinition.java | 52 ---- .../besu/enclave/TlsEnabledEnclaveTest.java | 144 ----------- .../enclave/TlsEnabledHttpServerFactory.java | 109 -------- .../hyperledger/besu/enclave/TlsHelpers.java | 98 ------- ...vGetPrivateTransactionIntegrationTest.java | 192 -------------- ...acyPrecompiledContractIntegrationTest.java | 244 ------------------ testutil/src/main/resources/enclave_key_0.key | 1 - 8 files changed, 1055 deletions(-) delete mode 100644 enclave/src/integration-test/java/org/hyperledger/besu/enclave/EnclaveTest.java delete mode 100644 enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsCertificateDefinition.java delete mode 100644 enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsEnabledEnclaveTest.java delete mode 100644 enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsEnabledHttpServerFactory.java delete mode 100644 enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsHelpers.java delete mode 100644 ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/PrivGetPrivateTransactionIntegrationTest.java delete mode 100644 ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java delete mode 100644 testutil/src/main/resources/enclave_key_0.key diff --git a/enclave/src/integration-test/java/org/hyperledger/besu/enclave/EnclaveTest.java b/enclave/src/integration-test/java/org/hyperledger/besu/enclave/EnclaveTest.java deleted file mode 100644 index b9b657e668..0000000000 --- a/enclave/src/integration-test/java/org/hyperledger/besu/enclave/EnclaveTest.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * 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.enclave; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchThrowable; - -import org.hyperledger.besu.enclave.types.PrivacyGroup; -import org.hyperledger.besu.enclave.types.ReceiveResponse; -import org.hyperledger.besu.enclave.types.SendResponse; -import org.hyperledger.enclave.testutil.EnclaveEncryptorType; -import org.hyperledger.enclave.testutil.EnclaveKeyConfiguration; -import org.hyperledger.enclave.testutil.TesseraTestHarness; -import org.hyperledger.enclave.testutil.TesseraTestHarnessFactory; - -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.TimeUnit; - -import com.google.common.collect.Lists; -import io.vertx.core.Vertx; -import org.awaitility.Awaitility; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -public class EnclaveTest { - - @TempDir private static Path folder; - - private static final String PAYLOAD = "a wonderful transaction"; - private static final String MOCK_KEY = "iOCzoGo5kwtZU0J41Z9xnGXHN6ZNukIa9MspvHtu3Jk="; - private Enclave enclave; - private Vertx vertx; - private EnclaveFactory factory; - - private TesseraTestHarness testHarness; - - @BeforeEach - public void setUp() throws Exception { - vertx = Vertx.vertx(); - factory = new EnclaveFactory(vertx); - - testHarness = - TesseraTestHarnessFactory.create( - "enclave", - Files.createTempDirectory(folder, "enclave"), - new EnclaveKeyConfiguration( - new String[] {"enclave_key_0.pub"}, - new String[] {"enclave_key_0.key"}, - EnclaveEncryptorType.NOOP), - Optional.empty()); - - testHarness.start(); - - enclave = factory.createVertxEnclave(testHarness.clientUrl()); - } - - @AfterEach - public void tearDown() { - testHarness.close(); - vertx.close(); - } - - @Test - public void testUpCheck() { - assertThat(enclave.upCheck()).isTrue(); - } - - @Test - public void testReceiveThrowsWhenPayloadDoesNotExist() { - final String publicKey = testHarness.getDefaultPublicKey(); - - final Throwable t = catchThrowable(() -> enclave.receive(MOCK_KEY, publicKey)); - - assertThat(t.getMessage()).isEqualTo("Message with hash was not found"); - } - - @Test - public void testSendAndReceive() { - final List publicKeys = testHarness.getPublicKeys(); - - final SendResponse sr = - enclave.send(PAYLOAD, publicKeys.get(0), Lists.newArrayList(publicKeys.get(0))); - - final ReceiveResponse rr = enclave.receive(sr.getKey(), publicKeys.get(0)); - assertThat(rr).isNotNull(); - assertThat(new String(rr.getPayload(), UTF_8)).isEqualTo(PAYLOAD); - assertThat(rr.getPrivacyGroupId()).isNotNull(); - } - - @Test - public void testSendWithPrivacyGroupAndReceive() { - final List publicKeys = testHarness.getPublicKeys(); - - final PrivacyGroup privacyGroupResponse = - enclave.createPrivacyGroup(publicKeys, publicKeys.get(0), "", ""); - - final SendResponse sr = - enclave.send(PAYLOAD, publicKeys.get(0), privacyGroupResponse.getPrivacyGroupId()); - - final ReceiveResponse rr = enclave.receive(sr.getKey(), publicKeys.get(0)); - assertThat(rr).isNotNull(); - assertThat(new String(rr.getPayload(), UTF_8)).isEqualTo(PAYLOAD); - assertThat(rr.getPrivacyGroupId()).isNotNull(); - } - - @Test - public void testCreateAndDeletePrivacyGroup() { - final List publicKeys = testHarness.getPublicKeys(); - final String name = "testName"; - final String description = "testDesc"; - - final PrivacyGroup privacyGroupResponse = - enclave.createPrivacyGroup(publicKeys, publicKeys.get(0), name, description); - - assertThat(privacyGroupResponse.getPrivacyGroupId()).isNotNull(); - assertThat(privacyGroupResponse.getName()).isEqualTo(name); - assertThat(privacyGroupResponse.getDescription()).isEqualTo(description); - assertThat(privacyGroupResponse.getType()).isEqualByComparingTo(PrivacyGroup.Type.PANTHEON); - - final String response = - enclave.deletePrivacyGroup(privacyGroupResponse.getPrivacyGroupId(), publicKeys.get(0)); - - assertThat(privacyGroupResponse.getPrivacyGroupId()).isEqualTo(response); - } - - @Test - public void testCreateFindDeleteFindPrivacyGroup() { - final List publicKeys = testHarness.getPublicKeys(); - final String name = "name"; - final String description = "desc"; - - final PrivacyGroup privacyGroupResponse = - enclave.createPrivacyGroup(publicKeys, publicKeys.get(0), name, description); - - assertThat(privacyGroupResponse.getPrivacyGroupId()).isNotNull(); - assertThat(privacyGroupResponse.getName()).isEqualTo(name); - assertThat(privacyGroupResponse.getDescription()).isEqualTo(description); - assertThat(privacyGroupResponse.getType()).isEqualTo(PrivacyGroup.Type.PANTHEON); - - Awaitility.await() - .atMost(5, TimeUnit.SECONDS) - .untilAsserted( - () -> { - final PrivacyGroup[] findPrivacyGroupResponse = enclave.findPrivacyGroup(publicKeys); - - assertThat(findPrivacyGroupResponse.length).isEqualTo(1); - assertThat(findPrivacyGroupResponse[0].getPrivacyGroupId()) - .isEqualTo(privacyGroupResponse.getPrivacyGroupId()); - }); - - final String response = - enclave.deletePrivacyGroup(privacyGroupResponse.getPrivacyGroupId(), publicKeys.get(0)); - - assertThat(privacyGroupResponse.getPrivacyGroupId()).isEqualTo(response); - - Awaitility.await() - .atMost(5, TimeUnit.SECONDS) - .untilAsserted( - () -> { - final PrivacyGroup[] findPrivacyGroupResponse = enclave.findPrivacyGroup(publicKeys); - - assertThat(findPrivacyGroupResponse.length).isEqualTo(0); - }); - } - - @Test - public void testCreateDeleteRetrievePrivacyGroup() { - final List publicKeys = testHarness.getPublicKeys(); - final String name = "name"; - final String description = "desc"; - - final PrivacyGroup privacyGroupResponse = - enclave.createPrivacyGroup(publicKeys, publicKeys.get(0), name, description); - - assertThat(privacyGroupResponse.getPrivacyGroupId()).isNotNull(); - assertThat(privacyGroupResponse.getName()).isEqualTo(name); - assertThat(privacyGroupResponse.getDescription()).isEqualTo(description); - assertThat(privacyGroupResponse.getType()).isEqualTo(PrivacyGroup.Type.PANTHEON); - - final PrivacyGroup retrievePrivacyGroup = - enclave.retrievePrivacyGroup(privacyGroupResponse.getPrivacyGroupId()); - - assertThat(retrievePrivacyGroup).usingRecursiveComparison().isEqualTo(privacyGroupResponse); - - final String response = - enclave.deletePrivacyGroup(privacyGroupResponse.getPrivacyGroupId(), publicKeys.get(0)); - - assertThat(privacyGroupResponse.getPrivacyGroupId()).isEqualTo(response); - } - - @Test - public void upcheckReturnsFalseIfNoResponseReceived() throws URISyntaxException { - assertThat(factory.createVertxEnclave(new URI("http://8.8.8.8:65535")).upCheck()).isFalse(); - } -} diff --git a/enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsCertificateDefinition.java b/enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsCertificateDefinition.java deleted file mode 100644 index ad1271e920..0000000000 --- a/enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsCertificateDefinition.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * 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.enclave; - -import java.io.File; -import java.net.URL; -import java.nio.file.Path; - -import com.google.common.io.Resources; - -public class TlsCertificateDefinition { - - private final File pkcs12File; - private final String password; - - public static TlsCertificateDefinition loadFromResource( - final String resourcePath, final String password) { - try { - final URL sslCertificate = Resources.getResource(resourcePath); - final Path keystorePath = Path.of(sslCertificate.getPath()); - - return new TlsCertificateDefinition(keystorePath.toFile(), password); - } catch (final Exception e) { - throw new RuntimeException("Failed to load TLS certificates", e); - } - } - - public TlsCertificateDefinition(final File pkcs12File, final String password) { - this.pkcs12File = pkcs12File; - this.password = password; - } - - public File getPkcs12File() { - return pkcs12File; - } - - public String getPassword() { - return password; - } -} diff --git a/enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsEnabledEnclaveTest.java b/enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsEnabledEnclaveTest.java deleted file mode 100644 index b594779306..0000000000 --- a/enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsEnabledEnclaveTest.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * 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.enclave; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; -import static org.hyperledger.besu.enclave.TlsHelpers.populateFingerprintFile; - -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.util.Optional; - -import io.vertx.core.Vertx; -import io.vertx.core.http.HttpServer; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class TlsEnabledEnclaveTest { - - private TlsEnabledHttpServerFactory serverFactory; - private Vertx vertx; - - final TlsCertificateDefinition httpServerCert = - TlsCertificateDefinition.loadFromResource("tls/cert1.pfx", "password"); - final TlsCertificateDefinition besuCert = - TlsCertificateDefinition.loadFromResource("tls/cert2.pfx", "password2"); - - public void shutdown() { - vertx.close(); - } - - @BeforeEach - public void setup() { - serverFactory = new TlsEnabledHttpServerFactory(); - this.vertx = Vertx.vertx(); - } - - @AfterEach - public void cleanup() { - serverFactory.shutdown(); - this.shutdown(); - } - - private Enclave createEnclave( - final int httpServerPort, final Path workDir, final boolean tlsEnabled) throws IOException { - - final Path serverFingerprintFile = workDir.resolve("server_known_clients"); - final Path besuCertPasswordFile = workDir.resolve("password_file"); - try { - populateFingerprintFile(serverFingerprintFile, httpServerCert, Optional.of(httpServerPort)); - Files.write(besuCertPasswordFile, besuCert.getPassword().getBytes(Charset.defaultCharset())); - - final EnclaveFactory factory = new EnclaveFactory(vertx); - if (tlsEnabled) { - final URI httpServerUri = new URI("https://localhost:" + httpServerPort); - return factory.createVertxEnclave( - httpServerUri, - besuCert.getPkcs12File().toPath(), - besuCertPasswordFile, - serverFingerprintFile); - } else { - return factory.createVertxEnclave(new URI("http://localhost:" + httpServerPort)); - } - } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException e) { - fail("unable to populate fingerprint file"); - return null; - } catch (URISyntaxException e) { - fail("unable to create URI"); - return null; - } - } - - @Test - public void nonTlsEnclaveCannotConnectToTlsServer() throws IOException { - - Path workDir = Files.createTempDirectory("test-certs"); - - // Note: the HttpServer always responds with a JsonRpcSuccess, result="I'm up". - final HttpServer httpServer = serverFactory.create(httpServerCert, besuCert, workDir, true); - - final Enclave enclave = createEnclave(httpServer.actualPort(), workDir, false); - - assertThat(enclave.upCheck()).isEqualTo(false); - } - - @Test - public void nonTlsEnclaveCanConnectToNonTlsServer() throws IOException { - - Path workDir = Files.createTempDirectory("test-certs"); - - // Note: the HttpServer always responds with a JsonRpcSuccess, result="I'm up". - final HttpServer httpServer = serverFactory.create(httpServerCert, besuCert, workDir, false); - - final Enclave enclave = createEnclave(httpServer.actualPort(), workDir, false); - - assertThat(enclave.upCheck()).isEqualTo(true); - } - - @Test - public void tlsEnclaveCannotConnectToNonTlsServer() throws IOException { - - Path workDir = Files.createTempDirectory("test-certs"); - - // Note: the HttpServer always responds with a JsonRpcSuccess, result="I'm up!". - final HttpServer httpServer = serverFactory.create(httpServerCert, besuCert, workDir, false); - - final Enclave enclave = createEnclave(httpServer.actualPort(), workDir, true); - - assertThat(enclave.upCheck()).isEqualTo(false); - } - - @Test - public void tlsEnclaveCanConnectToTlsServer() throws IOException { - - Path workDir = Files.createTempDirectory("test-certs"); - - // Note: the HttpServer always responds with a JsonRpcSuccess, result="I'm up". - final HttpServer httpServer = serverFactory.create(httpServerCert, besuCert, workDir, true); - - final Enclave enclave = createEnclave(httpServer.actualPort(), workDir, true); - - assertThat(enclave.upCheck()).isEqualTo(true); - } -} diff --git a/enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsEnabledHttpServerFactory.java b/enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsEnabledHttpServerFactory.java deleted file mode 100644 index 7c67aeb7b9..0000000000 --- a/enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsEnabledHttpServerFactory.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * 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.enclave; - -import static org.hyperledger.besu.enclave.TlsHelpers.populateFingerprintFile; - -import java.io.IOException; -import java.nio.file.Path; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import com.google.common.collect.Lists; -import io.netty.handler.codec.http.HttpHeaderValues; -import io.vertx.core.Vertx; -import io.vertx.core.http.ClientAuth; -import io.vertx.core.http.HttpMethod; -import io.vertx.core.http.HttpServer; -import io.vertx.core.http.HttpServerOptions; -import io.vertx.core.http.HttpServerResponse; -import io.vertx.core.net.PfxOptions; -import io.vertx.ext.web.Router; -import io.vertx.ext.web.RoutingContext; -import org.apache.tuweni.net.tls.VertxTrustOptions; - -class TlsEnabledHttpServerFactory { - - private final Vertx vertx; - private final List serversCreated = Lists.newArrayList(); - - TlsEnabledHttpServerFactory() { - this.vertx = Vertx.vertx(); - } - - void shutdown() { - serversCreated.forEach(HttpServer::close); - vertx.close(); - } - - HttpServer create( - final TlsCertificateDefinition serverCert, - final TlsCertificateDefinition acceptedClientCerts, - final Path workDir, - final boolean tlsEnabled) { - try { - - final Path serverFingerprintFile = workDir.resolve("server_known_clients"); - populateFingerprintFile(serverFingerprintFile, acceptedClientCerts, Optional.empty()); - - final HttpServerOptions web3HttpServerOptions = new HttpServerOptions(); - web3HttpServerOptions.setPort(0); - if (tlsEnabled) { - web3HttpServerOptions.setSsl(true); - web3HttpServerOptions.setClientAuth(ClientAuth.REQUIRED); - web3HttpServerOptions.setTrustOptions( - VertxTrustOptions.allowlistClients(serverFingerprintFile)); - web3HttpServerOptions.setPfxKeyCertOptions( - new PfxOptions() - .setPath(serverCert.getPkcs12File().toString()) - .setPassword(serverCert.getPassword())); - } - final Router router = Router.router(vertx); - router - .route(HttpMethod.GET, "/upcheck") - .produces(HttpHeaderValues.APPLICATION_JSON.toString()) - .handler(TlsEnabledHttpServerFactory::handleRequest); - - final HttpServer mockOrionHttpServer = vertx.createHttpServer(web3HttpServerOptions); - - final CompletableFuture serverConfigured = new CompletableFuture<>(); - mockOrionHttpServer.requestHandler(router).listen(result -> serverConfigured.complete(true)); - - serverConfigured.get(); - - serversCreated.add(mockOrionHttpServer); - return mockOrionHttpServer; - } catch (final KeyStoreException - | NoSuchAlgorithmException - | CertificateException - | IOException - | ExecutionException - | InterruptedException e) { - throw new RuntimeException("Failed to construct a TLS Enabled Server", e); - } - } - - private static void handleRequest(final RoutingContext context) { - final HttpServerResponse response = context.response(); - if (!response.closed()) { - response.end("I'm up!"); - } - } -} diff --git a/enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsHelpers.java b/enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsHelpers.java deleted file mode 100644 index 09002f8115..0000000000 --- a/enclave/src/integration-test/java/org/hyperledger/besu/enclave/TlsHelpers.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * 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.enclave; - -import org.hyperledger.besu.crypto.MessageDigestFactory; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.Enumeration; -import java.util.List; -import java.util.Locale; -import java.util.Optional; -import java.util.StringJoiner; - -import com.google.common.collect.Lists; - -public class TlsHelpers { - - private TlsHelpers() {} - - private static KeyStore loadP12KeyStore(final File pkcsFile, final String password) - throws KeyStoreException, NoSuchAlgorithmException, CertificateException { - final KeyStore store = KeyStore.getInstance("pkcs12"); - try (final InputStream keystoreStream = new FileInputStream(pkcsFile)) { - store.load(keystoreStream, password.toCharArray()); - } catch (IOException e) { - throw new RuntimeException("Unable to load keystore.", e); - } - return store; - } - - public static void populateFingerprintFile( - final Path knownClientsPath, - final TlsCertificateDefinition certDef, - final Optional serverPortToAppendToHostname) - throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException { - - final List certs = getCertsFromPkcs12(certDef); - final StringBuilder fingerprintsToAdd = new StringBuilder(); - final String portFragment = serverPortToAppendToHostname.map(port -> ":" + port).orElse(""); - for (final X509Certificate cert : certs) { - final String fingerprint = generateFingerprint(cert); - fingerprintsToAdd.append(String.format("localhost%s %s%n", portFragment, fingerprint)); - fingerprintsToAdd.append(String.format("127.0.0.1%s %s%n", portFragment, fingerprint)); - } - Files.writeString(knownClientsPath, fingerprintsToAdd.toString()); - } - - @SuppressWarnings("JdkObsolete") // java.util.Enumeration is baked into the Keystore API - public static List getCertsFromPkcs12(final TlsCertificateDefinition certDef) - throws KeyStoreException, NoSuchAlgorithmException, CertificateException { - final List results = Lists.newArrayList(); - - final KeyStore p12 = loadP12KeyStore(certDef.getPkcs12File(), certDef.getPassword()); - final Enumeration aliases = p12.aliases(); - while (aliases.hasMoreElements()) { - results.add((X509Certificate) p12.getCertificate(aliases.nextElement())); - } - return results; - } - - private static String generateFingerprint(final X509Certificate cert) - throws NoSuchAlgorithmException, CertificateEncodingException { - final MessageDigest md = MessageDigestFactory.create(MessageDigestFactory.SHA256_ALG); - md.update(cert.getEncoded()); - final byte[] digest = md.digest(); - - final StringJoiner joiner = new StringJoiner(":"); - for (final byte b : digest) { - joiner.add(String.format("%02X", b)); - } - - return joiner.toString().toLowerCase(Locale.ROOT); - } -} diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/PrivGetPrivateTransactionIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/PrivGetPrivateTransactionIntegrationTest.java deleted file mode 100644 index 9bb10629f3..0000000000 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/PrivGetPrivateTransactionIntegrationTest.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * 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.api.jsonrpc.methods.fork.frontier; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.assertj.core.api.Assertions.assertThat; -import static org.hyperledger.besu.ethereum.core.PrivateTransactionDataFixture.privateMarkerTransaction; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -import org.hyperledger.besu.crypto.KeyPair; -import org.hyperledger.besu.crypto.SignatureAlgorithm; -import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; -import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.enclave.Enclave; -import org.hyperledger.besu.enclave.EnclaveFactory; -import org.hyperledger.besu.enclave.types.SendResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacyIdProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetPrivateTransaction; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionLegacyResult; -import org.hyperledger.besu.ethereum.chain.Blockchain; -import org.hyperledger.besu.ethereum.chain.TransactionLocation; -import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.privacy.PrivacyController; -import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; -import org.hyperledger.besu.ethereum.privacy.RestrictedDefaultPrivacyController; -import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateStorage; -import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; -import org.hyperledger.besu.plugin.data.Restriction; -import org.hyperledger.enclave.testutil.EnclaveEncryptorType; -import org.hyperledger.enclave.testutil.EnclaveKeyConfiguration; -import org.hyperledger.enclave.testutil.TesseraTestHarness; -import org.hyperledger.enclave.testutil.TesseraTestHarnessFactory; - -import java.math.BigInteger; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Base64; -import java.util.Optional; - -import com.google.common.collect.Lists; -import io.vertx.core.Vertx; -import org.apache.tuweni.bytes.Bytes; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -public class PrivGetPrivateTransactionIntegrationTest { - - @TempDir private static Path folder; - private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; - - private final PrivacyIdProvider privacyIdProvider = (user) -> ENCLAVE_PUBLIC_KEY; - private final PrivateStateStorage privateStateStorage = mock(PrivateStateStorage.class); - private final Blockchain blockchain = mock(Blockchain.class); - - private final Address sender = - Address.fromHexString("0x0000000000000000000000000000000000000003"); - - private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance(); - - private final KeyPair KEY_PAIR = - signatureAlgorithm.createKeyPair( - signatureAlgorithm.createPrivateKey( - new BigInteger( - "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", 16))); - - private final PrivateTransaction privateTransaction = - PrivateTransaction.builder() - .nonce(0) - .gasPrice(Wei.of(1000)) - .gasLimit(3000000) - .to(null) - .value(Wei.ZERO) - .payload( - Bytes.fromHexString( - "0x608060405234801561001057600080fd5b5060d08061001f60003960" - + "00f3fe60806040526004361060485763ffffffff7c01000000" - + "00000000000000000000000000000000000000000000000000" - + "60003504166360fe47b18114604d5780636d4ce63c14607557" - + "5b600080fd5b348015605857600080fd5b5060736004803603" - + "6020811015606d57600080fd5b50356099565b005b34801560" - + "8057600080fd5b506087609e565b6040805191825251908190" - + "0360200190f35b600055565b6000549056fea165627a7a7230" - + "5820cb1d0935d14b589300b12fcd0ab849a7e9019c81da24d6" - + "daa4f6b2f003d1b0180029")) - .sender(sender) - .chainId(BigInteger.valueOf(2018)) - .privateFrom(Bytes.wrap(ENCLAVE_PUBLIC_KEY.getBytes(UTF_8))) - .privateFor( - Lists.newArrayList( - Bytes.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8)))) - .restriction(Restriction.RESTRICTED) - .signAndBuild(KEY_PAIR); - - private Vertx vertx = Vertx.vertx(); - private TesseraTestHarness testHarness; - private Enclave enclave; - private PrivacyController privacyController; - - @BeforeEach - public void setUp() throws Exception { - vertx = Vertx.vertx(); - - testHarness = - TesseraTestHarnessFactory.create( - "enclave", - Files.createTempDirectory(folder, "enclave"), - new EnclaveKeyConfiguration( - new String[] {"enclave_key_0.pub"}, - new String[] {"enclave_key_0.key"}, - EnclaveEncryptorType.NOOP), - Optional.empty()); - - testHarness.start(); - - final EnclaveFactory factory = new EnclaveFactory(vertx); - enclave = factory.createVertxEnclave(testHarness.clientUrl()); - - privacyController = - new RestrictedDefaultPrivacyController( - blockchain, privateStateStorage, enclave, null, null, null, null, null); - } - - @AfterEach - public void tearDown() { - testHarness.close(); - vertx.close(); - } - - @Test - public void returnsStoredPrivateTransaction() { - final PrivGetPrivateTransaction privGetPrivateTransaction = - new PrivGetPrivateTransaction(privacyController, privacyIdProvider); - - final Hash blockHash = Hash.ZERO; - final Transaction pmt = spy(privateMarkerTransaction()); - when(blockchain.getTransactionByHash(eq(pmt.getHash()))).thenReturn(Optional.of(pmt)); - when(blockchain.getTransactionLocation(eq(pmt.getHash()))) - .thenReturn(Optional.of(new TransactionLocation(blockHash, 0))); - - final BlockHeader blockHeader = mock(BlockHeader.class); - when(blockHeader.getHash()).thenReturn(blockHash); - when(blockchain.getBlockHeader(eq(blockHash))).thenReturn(Optional.of(blockHeader)); - - final BytesValueRLPOutput bvrlp = new BytesValueRLPOutput(); - privateTransaction.writeTo(bvrlp); - - final String payload = Base64.getEncoder().encodeToString(bvrlp.encoded().toArrayUnsafe()); - final ArrayList to = Lists.newArrayList("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="); - final SendResponse sendResponse = enclave.send(payload, ENCLAVE_PUBLIC_KEY, to); - - final Bytes hexKey = Bytes.fromBase64String(sendResponse.getKey()); - when(pmt.getPayload()).thenReturn(hexKey); - - final Object[] params = new Object[] {pmt.getHash()}; - - final JsonRpcRequestContext request = - new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_getPrivateTransaction", params)); - - final JsonRpcSuccessResponse response = - (JsonRpcSuccessResponse) privGetPrivateTransaction.response(request); - final PrivateTransactionLegacyResult result = - (PrivateTransactionLegacyResult) response.getResult(); - - assertThat(new PrivateTransactionLegacyResult(this.privateTransaction)) - .usingRecursiveComparison() - .isEqualTo(result); - } -} diff --git a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java deleted file mode 100644 index a5ee5f068e..0000000000 --- a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * 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.mainnet.precompiles.privacy; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchThrowable; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.enclave.Enclave; -import org.hyperledger.besu.enclave.EnclaveFactory; -import org.hyperledger.besu.enclave.types.SendResponse; -import org.hyperledger.besu.ethereum.core.Block; -import org.hyperledger.besu.ethereum.core.BlockDataGenerator; -import org.hyperledger.besu.ethereum.core.MutableWorldState; -import org.hyperledger.besu.ethereum.core.PrivateTransactionDataFixture; -import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; -import org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils; -import org.hyperledger.besu.ethereum.privacy.PrivateStateGenesisAllocator; -import org.hyperledger.besu.ethereum.privacy.PrivateStateRootResolver; -import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; -import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor; -import org.hyperledger.besu.ethereum.privacy.storage.PrivacyGroupHeadBlockMap; -import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater; -import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateStorage; -import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; -import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; -import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; -import org.hyperledger.besu.evm.frame.MessageFrame; -import org.hyperledger.besu.evm.gascalculator.SpuriousDragonGasCalculator; -import org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup; -import org.hyperledger.besu.evm.precompile.PrecompiledContract; -import org.hyperledger.besu.evm.tracing.OperationTracer; -import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import org.hyperledger.enclave.testutil.EnclaveEncryptorType; -import org.hyperledger.enclave.testutil.EnclaveKeyConfiguration; -import org.hyperledger.enclave.testutil.TesseraTestHarness; -import org.hyperledger.enclave.testutil.TesseraTestHarnessFactory; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -import com.google.common.collect.Lists; -import io.vertx.core.Vertx; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -public class PrivacyPrecompiledContractIntegrationTest { - - // this tempDir is deliberately static - @TempDir private static Path folder; - - private static final Bytes VALID_PRIVATE_TRANSACTION_RLP = - Bytes.fromHexString( - "0xf90113800182520894095e7baea6a6c7c4c2dfeb977efac326af552d87" - + "a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - + "ffff801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d" - + "495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab94" - + "9f53faa07bd2c804ac41316156744d784c4355486d425648586f5a7a7a4267" - + "5062572f776a3561784470573958386c393153476f3df85aac41316156744d" - + "784c4355486d425648586f5a7a7a42675062572f776a356178447057395838" - + "6c393153476f3dac4b6f32625671442b6e4e6c4e594c35454537793349644f" - + "6e766966746a69697a706a52742b4854754642733d8a726573747269637465" - + "64"); - private static final String DEFAULT_OUTPUT = "0x01"; - - private static Enclave enclave; - private static MessageFrame messageFrame; - - private static TesseraTestHarness testHarness; - private static WorldStateArchive worldStateArchive; - private static PrivateStateStorage privateStateStorage; - private static final Vertx vertx = Vertx.vertx(); - - private PrivateTransactionProcessor mockPrivateTxProcessor() { - final PrivateTransactionProcessor mockPrivateTransactionProcessor = - mock(PrivateTransactionProcessor.class); - final TransactionProcessingResult result = - TransactionProcessingResult.successful( - null, 0, 0, Bytes.fromHexString(DEFAULT_OUTPUT), null); - when(mockPrivateTransactionProcessor.processTransaction( - nullable(WorldUpdater.class), - nullable(WorldUpdater.class), - nullable(ProcessableBlockHeader.class), - nullable(Hash.class), - nullable(PrivateTransaction.class), - nullable(Address.class), - nullable(OperationTracer.class), - nullable(BlockHashLookup.class), - nullable(Bytes.class))) - .thenReturn(result); - - return mockPrivateTransactionProcessor; - } - - @BeforeAll - public static void setUpOnce() throws Exception { - - testHarness = - TesseraTestHarnessFactory.create( - "enclave", - Files.createTempDirectory(folder, "enclave"), - new EnclaveKeyConfiguration( - new String[] {"enclave_key_0.pub"}, - new String[] {"enclave_key_1.key"}, - EnclaveEncryptorType.NOOP), - Optional.empty()); - - testHarness.start(); - - final EnclaveFactory factory = new EnclaveFactory(vertx); - enclave = factory.createVertxEnclave(testHarness.clientUrl()); - messageFrame = mock(MessageFrame.class); - final BlockDataGenerator blockGenerator = new BlockDataGenerator(); - final Block genesis = blockGenerator.genesisBlock(); - final Block block = - blockGenerator.block( - new BlockDataGenerator.BlockOptions().setParentHash(genesis.getHeader().getHash())); - when(messageFrame.getBlockValues()).thenReturn(block.getHeader()); - final PrivateMetadataUpdater privateMetadataUpdater = mock(PrivateMetadataUpdater.class); - when(privateMetadataUpdater.getPrivateBlockMetadata(any())).thenReturn(null); - when(privateMetadataUpdater.getPrivacyGroupHeadBlockMap()) - .thenReturn(PrivacyGroupHeadBlockMap.empty()); - when(messageFrame.getContextVariable( - eq(PrivateStateUtils.KEY_IS_PERSISTING_PRIVATE_STATE), anyBoolean())) - .thenReturn(false); - when(messageFrame.getContextVariable(eq(PrivateStateUtils.KEY_PRIVATE_METADATA_UPDATER))) - .thenReturn(privateMetadataUpdater); - when(messageFrame.hasContextVariable(eq(PrivateStateUtils.KEY_PRIVATE_METADATA_UPDATER))) - .thenReturn(true); - - worldStateArchive = mock(WorldStateArchive.class); - final MutableWorldState mutableWorldState = mock(MutableWorldState.class); - when(mutableWorldState.updater()).thenReturn(mock(WorldUpdater.class)); - when(worldStateArchive.getMutable()).thenReturn(mutableWorldState); - when(worldStateArchive.getMutable(any(), any())).thenReturn(Optional.of(mutableWorldState)); - - privateStateStorage = mock(PrivateStateStorage.class); - final PrivateStateStorage.Updater storageUpdater = mock(PrivateStateStorage.Updater.class); - when(privateStateStorage.getPrivacyGroupHeadBlockMap(any())) - .thenReturn(Optional.of(PrivacyGroupHeadBlockMap.empty())); - when(storageUpdater.putPrivateBlockMetadata( - nullable(Bytes32.class), nullable(Bytes32.class), any())) - .thenReturn(storageUpdater); - when(storageUpdater.putTransactionReceipt( - nullable(Bytes32.class), nullable(Bytes32.class), any())) - .thenReturn(storageUpdater); - when(privateStateStorage.updater()).thenReturn(storageUpdater); - } - - @AfterAll - public static void tearDownOnce() { - testHarness.stop(); - vertx.close(); - } - - @Test - public void testUpCheck() { - assertThat(enclave.upCheck()).isTrue(); - } - - @Test - public void testSendAndReceive() { - final List publicKeys = testHarness.getPublicKeys(); - - final PrivateTransaction privateTransaction = - PrivateTransactionDataFixture.privateContractDeploymentTransactionBesu(publicKeys.get(0)); - final BytesValueRLPOutput bytesValueRLPOutput = new BytesValueRLPOutput(); - privateTransaction.writeTo(bytesValueRLPOutput); - - final String s = bytesValueRLPOutput.encoded().toBase64String(); - final SendResponse sr = - enclave.send(s, publicKeys.get(0), Lists.newArrayList(publicKeys.get(0))); - - final PrivacyPrecompiledContract privacyPrecompiledContract = - new PrivacyPrecompiledContract( - new SpuriousDragonGasCalculator(), - enclave, - worldStateArchive, - new PrivateStateRootResolver(privateStateStorage), - new PrivateStateGenesisAllocator( - false, (privacyGroupId, blockNumber) -> Collections::emptyList), - false, - "IntegrationTest"); - - privacyPrecompiledContract.setPrivateTransactionProcessor(mockPrivateTxProcessor()); - - final PrecompiledContract.PrecompileContractResult result = - privacyPrecompiledContract.computePrecompile( - Bytes.fromBase64String(sr.getKey()), messageFrame); - final Bytes actual = result.getOutput(); - - assertThat(actual).isEqualTo(Bytes.fromHexString(DEFAULT_OUTPUT)); - } - - @Test - public void testNoPrivateKeyError() throws RuntimeException { - final List publicKeys = testHarness.getPublicKeys(); - publicKeys.add("noPrivateKey"); - - final String s = VALID_PRIVATE_TRANSACTION_RLP.toBase64String(); - - final Throwable thrown = catchThrowable(() -> enclave.send(s, publicKeys.get(0), publicKeys)); - - assertThat(thrown).hasMessageContaining("Index 9 out of bounds for length 9"); - } - - @Test - public void testWrongPrivateKeyError() throws RuntimeException { - final List publicKeys = testHarness.getPublicKeys(); - publicKeys.add("noPrivateKenoPrivateKenoPrivateKenoPrivateK"); - - final String s = VALID_PRIVATE_TRANSACTION_RLP.toBase64String(); - - final Throwable thrown = catchThrowable(() -> enclave.send(s, publicKeys.get(0), publicKeys)); - - assertThat(thrown).hasMessageContaining("Recipient not found for key:"); - } -} diff --git a/testutil/src/main/resources/enclave_key_0.key b/testutil/src/main/resources/enclave_key_0.key deleted file mode 100644 index eaae9b0867..0000000000 --- a/testutil/src/main/resources/enclave_key_0.key +++ /dev/null @@ -1 +0,0 @@ -{"data":{"bytes":"hBsuQsGJzx4QHmFmBkNoI7YGnTmaZP4P+wBOdu56ljk="},"type":"unlocked"} \ No newline at end of file From 874cba016db3ef3c64df9d2ccf0b2b4a32d5d0f8 Mon Sep 17 00:00:00 2001 From: Matt Whitehead Date: Mon, 23 Sep 2024 11:58:47 +0100 Subject: [PATCH 11/12] Update protobuf to 32.25.5 to resolve CVE-2024-7254 (#7664) Signed-off-by: Matthew Whitehead --- gradle/verification-metadata.xml | 36 ++++++++++++++++++++++++++++++++ gradle/versions.gradle | 2 ++ 2 files changed, 38 insertions(+) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 3778a2d60a..7f6a58b66e 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -1023,6 +1023,11 @@ + + + + + @@ -1033,6 +1038,11 @@ + + + + + @@ -1049,6 +1059,14 @@ + + + + + + + + @@ -1062,6 +1080,14 @@ + + + + + + + + @@ -1080,6 +1106,11 @@ + + + + + @@ -1090,6 +1121,11 @@ + + + + + diff --git a/gradle/versions.gradle b/gradle/versions.gradle index b7a286e69a..634c29b1e1 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -25,6 +25,8 @@ dependencyManagement { dependency 'com.github.ben-manes.caffeine:caffeine:3.1.8' + dependency 'com.google.protobuf:protobuf-java:3.25.5' + dependency 'com.github.oshi:oshi-core:6.6.3' dependency 'com.google.auto.service:auto-service:1.1.1' From 0d6395515890280c29ee2402c03b1ee81bde3bab Mon Sep 17 00:00:00 2001 From: Rafael Matias Date: Mon, 23 Sep 2024 14:34:20 +0200 Subject: [PATCH 12/12] Docker: Only switch user if the current user is root (#7654) * Update entrypoint script for Dockerfile to only switch user if its running as root Signed-off-by: Rafael Matias * make root user check at the beginning Signed-off-by: Rafael Matias --------- Signed-off-by: Rafael Matias --- besu/src/main/scripts/besu-entry.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/besu/src/main/scripts/besu-entry.sh b/besu/src/main/scripts/besu-entry.sh index ed3687b229..ee11bfbffc 100755 --- a/besu/src/main/scripts/besu-entry.sh +++ b/besu/src/main/scripts/besu-entry.sh @@ -14,6 +14,14 @@ ## SPDX-License-Identifier: Apache-2.0 ## +# Construct the command as a single string +COMMAND="/opt/besu/bin/besu $@" + +# Check if current user is not root. If not, run the command as is. +if [ "$(id -u)" -ne 0 ]; then + exec /bin/bash -c "$COMMAND" +fi + # Run Besu first to get paths needing permission adjustment output=$(/opt/besu/bin/besu --print-paths-and-exit $BESU_USER_NAME "$@") @@ -41,9 +49,5 @@ echo "$output" | while IFS=: read -r prefix path accessType; do fi done -# Finally, run Besu with the actual arguments passed to the container -# Construct the command as a single string -COMMAND="/opt/besu/bin/besu $@" - # Switch to the besu user and execute the command -exec su -s /bin/bash $BESU_USER_NAME -c "$COMMAND" +exec su -s /bin/bash "$BESU_USER_NAME" -c "$COMMAND"