From 094fbb945358292a9706dc3be3dea62e0bee73bb Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Thu, 22 Feb 2024 13:59:53 +1000 Subject: [PATCH 1/3] Use Invalid payload attributes error code (#6582) * invalid payload error code * use non-zero timestamp * use invalidPayloadAttributes error for V2 if non-null beacon root pre cancun Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane --- ...repare_payload_invalid_null_withdrawals.json | 4 ++-- .../engine/EngineForkchoiceUpdatedV2.java | 11 +++++++++-- .../engine/EngineForkchoiceUpdatedV3.java | 17 ++++++++++++----- .../AbstractEngineForkchoiceUpdatedTest.java | 2 +- .../engine/EngineForkchoiceUpdatedV2Test.java | 6 ++++++ 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/shanghai/test-cases/05_shanghai_prepare_payload_invalid_null_withdrawals.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/shanghai/test-cases/05_shanghai_prepare_payload_invalid_null_withdrawals.json index ac5947c79be..23ddea33af0 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/shanghai/test-cases/05_shanghai_prepare_payload_invalid_null_withdrawals.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/shanghai/test-cases/05_shanghai_prepare_payload_invalid_null_withdrawals.json @@ -20,8 +20,8 @@ "jsonrpc" : "2.0", "id" : 67, "error" : { - "code" : -32602, - "message" : "Invalid params" + "code" : -38003, + "message" : "Invalid payload attributes" } }, "statusCode" : 200 diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2.java index b6406a3e662..77ca45df043 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2.java @@ -56,14 +56,21 @@ protected Optional isPayloadAttributesValid( || payloadAttributes.getParentBeaconBlockRoot().isEmpty()) { return Optional.of(new JsonRpcErrorResponse(requestId, RpcErrorType.UNSUPPORTED_FORK)); } else { - return Optional.of(new JsonRpcErrorResponse(requestId, RpcErrorType.INVALID_PARAMS)); + return Optional.of( + new JsonRpcErrorResponse(requestId, RpcErrorType.INVALID_PAYLOAD_ATTRIBUTES)); } } else if (payloadAttributes.getParentBeaconBlockRoot() != null) { LOG.error( "Parent beacon block root hash present in payload attributes before cancun hardfork"); - return Optional.of(new JsonRpcErrorResponse(requestId, RpcErrorType.INVALID_PARAMS)); + return Optional.of( + new JsonRpcErrorResponse(requestId, RpcErrorType.INVALID_PAYLOAD_ATTRIBUTES)); } else { return Optional.empty(); } } + + @Override + protected RpcErrorType getInvalidPayloadError() { + return RpcErrorType.INVALID_PAYLOAD_ATTRIBUTES; + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java index c070d220854..51672d7280e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java @@ -56,16 +56,16 @@ protected ValidationResult validateParameter( final EngineForkchoiceUpdatedParameter fcuParameter, final Optional maybePayloadAttributes) { if (fcuParameter.getHeadBlockHash() == null) { - return ValidationResult.invalid(RpcErrorType.INVALID_PARAMS, "Missing head block hash"); + return ValidationResult.invalid(getInvalidPayloadError(), "Missing head block hash"); } else if (fcuParameter.getSafeBlockHash() == null) { - return ValidationResult.invalid(RpcErrorType.INVALID_PARAMS, "Missing safe block hash"); + return ValidationResult.invalid(getInvalidPayloadError(), "Missing safe block hash"); } else if (fcuParameter.getFinalizedBlockHash() == null) { - return ValidationResult.invalid(RpcErrorType.INVALID_PARAMS, "Missing finalized block hash"); + return ValidationResult.invalid(getInvalidPayloadError(), "Missing finalized block hash"); } if (maybePayloadAttributes.isPresent()) { if (maybePayloadAttributes.get().getParentBeaconBlockRoot() == null) { return ValidationResult.invalid( - RpcErrorType.INVALID_PARAMS, "Missing parent beacon block root hash"); + getInvalidPayloadError(), "Missing parent beacon block root hash"); } } return ValidationResult.valid(); @@ -93,11 +93,18 @@ protected Optional isPayloadAttributesValid( if (payloadAttributes.getParentBeaconBlockRoot() == null) { LOG.error( "Parent beacon block root hash not present in payload attributes after cancun hardfork"); - return Optional.of(new JsonRpcErrorResponse(requestId, RpcErrorType.INVALID_PARAMS)); + return Optional.of(new JsonRpcErrorResponse(requestId, getInvalidPayloadError())); + } else if (payloadAttributes.getTimestamp().longValue() == 0) { + return Optional.of(new JsonRpcErrorResponse(requestId, getInvalidPayloadError())); } else if (payloadAttributes.getTimestamp() < cancun.get().milestone()) { return Optional.of(new JsonRpcErrorResponse(requestId, RpcErrorType.UNSUPPORTED_FORK)); } else { return Optional.empty(); } } + + @Override + protected RpcErrorType getInvalidPayloadError() { + return RpcErrorType.INVALID_PAYLOAD_ATTRIBUTES; + } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java index 249a12d9f0b..931d2259875 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java @@ -454,7 +454,7 @@ public void shouldIgnoreUpdateToOldHeadAndNotPreparePayload() { @Test public void shouldReturnInvalidIfPayloadTimestampNotGreaterThanHead() { - BlockHeader mockParent = blockHeaderBuilder.number(9L).buildHeader(); + BlockHeader mockParent = blockHeaderBuilder.timestamp(99).number(9L).buildHeader(); BlockHeader mockHeader = blockHeaderBuilder.number(10L).parentHash(mockParent.getHash()).buildHeader(); setupValidForkchoiceUpdate(mockHeader); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2Test.java index 77249934113..4cb17eab4f7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV2Test.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -42,4 +43,9 @@ public void shouldReturnExpectedMethodName() { protected String getMethodName() { return RpcMethod.ENGINE_FORKCHOICE_UPDATED_V2.getMethodName(); } + + @Override + protected RpcErrorType expectedInvalidPayloadError() { + return RpcErrorType.INVALID_PAYLOAD_ATTRIBUTES; + } } From 4815be8f6dfbe4a874f0cc83e75b08967ca9c7ee Mon Sep 17 00:00:00 2001 From: Matt Whitehead Date: Thu, 22 Feb 2024 14:32:54 +0000 Subject: [PATCH 2/3] During version check, create data dir if it doesn't exist (#6605) Signed-off-by: Matthew Whitehead --- .../besu/ethereum/core/VersionMetadata.java | 9 ++++++++- .../besu/ethereum/core/VersionMetadataTest.java | 11 +++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/VersionMetadata.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/VersionMetadata.java index 0723fda97a0..afa07cbf84b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/VersionMetadata.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/VersionMetadata.java @@ -67,7 +67,14 @@ public void writeToDirectory(final Path dataDir) throws IOException { } private static File getDefaultMetadataFile(final Path dataDir) { - return dataDir.resolve(METADATA_FILENAME).toFile(); + File metaDataFile = dataDir.resolve(METADATA_FILENAME).toFile(); + + // Create the data dir here if it doesn't exist yet + if (!metaDataFile.getParentFile().exists()) { + LOG.info("Data directory {} does not exist - creating it", dataDir); + metaDataFile.getParentFile().mkdirs(); + } + return metaDataFile; } private static VersionMetadata resolveVersionMetadata(final File metadataFile) diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/VersionMetadataTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/VersionMetadataTest.java index a506be214a9..0cebcd4bda8 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/VersionMetadataTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/VersionMetadataTest.java @@ -49,6 +49,17 @@ void metaFileShouldContain() throws Exception { assertThat(versionMetadata.getBesuVersion()).isEqualTo("23.10.3"); } + @Test + void dataDirShouldBeCreatedIfNotPresent() throws Exception { + Files.deleteIfExists(temporaryFolder); + assertThat(Files.exists(temporaryFolder)).isFalse(); + + final VersionMetadata versionMetadata = VersionMetadata.lookUpFrom(temporaryFolder); + assertThat(versionMetadata).isNotNull(); + + assertThat(Files.exists(temporaryFolder)).isTrue(); + } + @Test void compatibilityCheckShouldThrowExceptionIfEnabled() throws Exception { // The version file says the last version to start was 23.10.3 From 3538c55a37ffae6ea4ea87e90c107c538fc919dd Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Mon, 26 Feb 2024 12:10:45 +0100 Subject: [PATCH 3/3] Extend Blockchain service (#6592) Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 11 ++++ .../org/hyperledger/besu/cli/BesuCommand.java | 17 ++++--- .../besu/services/BlockchainServiceImpl.java | 51 ++++++++++++++++--- .../besu/cli/CommandTestAbstract.java | 4 +- plugin-api/build.gradle | 2 +- .../plugin/services/BlockchainService.java | 24 +++++++++ 6 files changed, 95 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a9a2a4eadb..6122cd3bbb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## 24.2.1-SNAPSHOT + +### Breaking Changes + +### Deprecations + +### Additions and Improvements +- Extend `Blockchain` service [#6592](https://github.com/hyperledger/besu/pull/6592) + +### Bug fixes + ## 24.2.0-SNAPSHOT ### Breaking Changes diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index f4b08e4f688..bcb0ce68576 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -373,6 +373,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable { private final TransactionSelectionServiceImpl transactionSelectionServiceImpl; private final PluginTransactionValidatorServiceImpl transactionValidatorServiceImpl; + private final BlockchainServiceImpl blockchainServiceImpl; static class P2PDiscoveryOptionGroup { @@ -957,7 +958,8 @@ public BesuCommand( new PkiBlockCreationConfigurationProvider(), new RpcEndpointServiceImpl(), new TransactionSelectionServiceImpl(), - new PluginTransactionValidatorServiceImpl()); + new PluginTransactionValidatorServiceImpl(), + new BlockchainServiceImpl()); } /** @@ -979,6 +981,7 @@ public BesuCommand( * @param rpcEndpointServiceImpl instance of RpcEndpointServiceImpl * @param transactionSelectionServiceImpl instance of TransactionSelectionServiceImpl * @param transactionValidatorServiceImpl instance of TransactionValidatorServiceImpl + * @param blockchainServiceImpl instance of BlockchainServiceImpl */ @VisibleForTesting protected BesuCommand( @@ -997,7 +1000,8 @@ protected BesuCommand( final PkiBlockCreationConfigurationProvider pkiBlockCreationConfigProvider, final RpcEndpointServiceImpl rpcEndpointServiceImpl, final TransactionSelectionServiceImpl transactionSelectionServiceImpl, - final PluginTransactionValidatorServiceImpl transactionValidatorServiceImpl) { + final PluginTransactionValidatorServiceImpl transactionValidatorServiceImpl, + final BlockchainServiceImpl blockchainServiceImpl) { this.besuComponent = besuComponent; this.logger = besuComponent.getBesuCommandLogger(); this.rlpBlockImporter = rlpBlockImporter; @@ -1017,6 +1021,7 @@ protected BesuCommand( this.rpcEndpointServiceImpl = rpcEndpointServiceImpl; this.transactionSelectionServiceImpl = transactionSelectionServiceImpl; this.transactionValidatorServiceImpl = transactionValidatorServiceImpl; + this.blockchainServiceImpl = blockchainServiceImpl; } /** @@ -1208,6 +1213,7 @@ private void preparePlugins() { TransactionSelectionService.class, transactionSelectionServiceImpl); besuPluginContext.addService( PluginTransactionValidatorService.class, transactionValidatorServiceImpl); + besuPluginContext.addService(BlockchainService.class, blockchainServiceImpl); // register built-in plugins rocksDBPlugin = new RocksDBPlugin(); @@ -1288,6 +1294,9 @@ private Runner buildRunner() { } private void startPlugins() { + blockchainServiceImpl.init( + besuController.getProtocolContext(), besuController.getProtocolSchedule()); + besuPluginContext.addService( BesuEvents.class, new BesuEventsImpl( @@ -1297,10 +1306,6 @@ private void startPlugins() { besuController.getSyncState())); besuPluginContext.addService(MetricsSystem.class, getMetricsSystem()); - besuPluginContext.addService( - BlockchainService.class, - new BlockchainServiceImpl(besuController.getProtocolContext().getBlockchain())); - besuPluginContext.addService( TraceService.class, new TraceServiceImpl( diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockchainServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockchainServiceImpl.java index a3b37a6665a..aa1c6a2128b 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockchainServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockchainServiceImpl.java @@ -15,8 +15,13 @@ package org.hyperledger.besu.services; -import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; +import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.plugin.Unstable; import org.hyperledger.besu.plugin.data.BlockContext; import org.hyperledger.besu.plugin.data.BlockHeader; @@ -29,15 +34,21 @@ @Unstable public class BlockchainServiceImpl implements BlockchainService { - private final Blockchain blockchain; + private ProtocolContext protocolContext; + private ProtocolSchedule protocolSchedule; + + /** Create a new instance */ + public BlockchainServiceImpl() {} /** * Instantiates a new Blockchain service. * - * @param blockchain the blockchain + * @param protocolContext the protocol context + * @param protocolSchedule the protocol schedule */ - public BlockchainServiceImpl(final Blockchain blockchain) { - this.blockchain = blockchain; + public void init(final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule) { + this.protocolContext = protocolContext; + this.protocolSchedule = protocolSchedule; } /** @@ -48,11 +59,39 @@ public BlockchainServiceImpl(final Blockchain blockchain) { */ @Override public Optional getBlockByNumber(final long number) { - return blockchain + return protocolContext + .getBlockchain() .getBlockByNumber(number) .map(block -> blockContext(block::getHeader, block::getBody)); } + @Override + public Hash getChainHeadHash() { + return protocolContext.getBlockchain().getChainHeadHash(); + } + + @Override + public BlockHeader getChainHeadHeader() { + return protocolContext.getBlockchain().getChainHeadHeader(); + } + + @Override + public Optional getNextBlockBaseFee() { + final var chainHeadHeader = protocolContext.getBlockchain().getChainHeadHeader(); + final var protocolSpec = + protocolSchedule.getForNextBlockHeader(chainHeadHeader, System.currentTimeMillis()); + return Optional.of(protocolSpec.getFeeMarket()) + .filter(FeeMarket::implementsBaseFee) + .map(BaseFeeMarket.class::cast) + .map( + feeMarket -> + feeMarket.computeBaseFee( + chainHeadHeader.getNumber() + 1, + chainHeadHeader.getBaseFee().orElse(Wei.ZERO), + chainHeadHeader.getGasUsed(), + feeMarket.targetGasUsed(chainHeadHeader))); + } + private static BlockContext blockContext( final Supplier blockHeaderSupplier, final Supplier blockBodySupplier) { diff --git a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java index 34c9d44e0fa..331f7d54a98 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -83,6 +83,7 @@ import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.services.BesuConfigurationImpl; import org.hyperledger.besu.services.BesuPluginContextImpl; +import org.hyperledger.besu.services.BlockchainServiceImpl; import org.hyperledger.besu.services.PermissioningServiceImpl; import org.hyperledger.besu.services.PluginTransactionValidatorServiceImpl; import org.hyperledger.besu.services.PrivacyPluginServiceImpl; @@ -564,7 +565,8 @@ public static class TestBesuCommand extends BesuCommand { pkiBlockCreationConfigProvider, rpcEndpointServiceImpl, new TransactionSelectionServiceImpl(), - new PluginTransactionValidatorServiceImpl()); + new PluginTransactionValidatorServiceImpl(), + new BlockchainServiceImpl()); } @Override diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index 9184bb57060..46611fc29d0 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -69,7 +69,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'f6P3+XG9GjPYEg7zrXHlujoE2/4axgd+EjKGDDJVVp8=' + knownHash = 'Pi7Veo9W9kmjDJJNB89UTUXbYyRmoN6osK/tD163h3E=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockchainService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockchainService.java index e9356ae76ef..76f66aba6ca 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockchainService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockchainService.java @@ -14,8 +14,11 @@ */ package org.hyperledger.besu.plugin.services; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.plugin.Unstable; import org.hyperledger.besu.plugin.data.BlockContext; +import org.hyperledger.besu.plugin.data.BlockHeader; import java.util.Optional; @@ -29,4 +32,25 @@ public interface BlockchainService extends BesuService { * @return the BlockContext */ Optional getBlockByNumber(final long number); + + /** + * Get the hash of the chain head + * + * @return chain head hash + */ + Hash getChainHeadHash(); + + /** + * Get the block header of the chain head + * + * @return chain head block header + */ + BlockHeader getChainHeadHeader(); + + /** + * Return the base fee for the next block + * + * @return base fee of the next block or empty if the fee market does not support base fee + */ + Optional getNextBlockBaseFee(); }