From ffd593d72ba404ad4f5c4b263ad4a1a111be8042 Mon Sep 17 00:00:00 2001 From: Simon Dudley Date: Tue, 7 Jan 2025 11:19:26 +1000 Subject: [PATCH 1/4] Remove EIP-7742 (#8083) This EIP was removed and equivalent functionality replaced by EIP-7840. --- Revert "Rename targetBlobCount to targetBlobsPerBlock (#7981)" This reverts commit 16713067490dc99ad36b21fa3d85d9dc639030ef. Revert "EIP-7742: Add target_blob_count to block header (#7808)" This reverts commit f855d5b72fb5e44977d995f48872cdb976333711. Signed-off-by: Simon Dudley --- .../besu/tests/acceptance/dsl/BlockUtils.java | 1 - .../ExecutionEnginePragueAcceptanceTest.java | 3 --- .../AbstractBftBesuControllerBuilderTest.java | 1 - .../CliqueBesuControllerBuilderTest.java | 1 - .../besu/services/BesuEventsImplTest.java | 2 +- .../besu/config/GenesisConfig.java | 11 ---------- .../api/jsonrpc/JsonRpcResponseKey.java | 3 +-- .../api/jsonrpc/JsonRpcResponseUtils.java | 6 ------ .../engine/AbstractEngineNewPayload.java | 1 - .../jsonrpc/internal/results/BlockResult.java | 7 ------- .../internal/methods/EthGasPriceTest.java | 1 - .../methods/EthMaxPriorityFeePerGasTest.java | 1 - ...neExchangeTransitionConfigurationTest.java | 1 - .../query/BlockchainQueriesLogCacheTest.java | 1 - .../cache/TransactionLogBloomCacherTest.java | 2 -- .../besu/ethereum/chain/GenesisState.java | 7 ------- .../besu/ethereum/core/BlockHeader.java | 15 +------------- .../ethereum/core/BlockHeaderBuilder.java | 20 +++---------------- .../ethereum/core/ProcessableBlockHeader.java | 20 +------------------ .../ethereum/core/SealableBlockHeader.java | 7 ++----- .../ethereum/core/BlockHeaderTestFixture.java | 8 -------- .../besu/ethereum/chain/GenesisStateTest.java | 12 ++++------- .../diffbased/bonsai/LogRollingTests.java | 2 -- .../besu/ethereum/chain/genesis_prague.json | 3 +-- .../eth/messages/MessageWrapperTest.java | 1 - .../backwardsync/ChainForTestCreator.java | 3 --- .../BlockchainReferenceTestCaseSpec.java | 1 - .../referencetests/ReferenceTestEnv.java | 1 - plugin-api/build.gradle | 2 +- .../plugin/data/ProcessableBlockHeader.java | 12 ----------- 30 files changed, 15 insertions(+), 141 deletions(-) diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java index 29f60dd74a6..3a4ca71002b 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java @@ -58,7 +58,6 @@ public static BlockHeader createBlockHeader( null, null, null, - null, blockHeaderFunctions); } } diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEnginePragueAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEnginePragueAcceptanceTest.java index f38a192d4df..966c02bebde 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEnginePragueAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEnginePragueAcceptanceTest.java @@ -20,11 +20,8 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.params.provider.Arguments; -// TODO SLD -@Disabled("TODO SLD - Enable when Prague spec is finalized") public class ExecutionEnginePragueAcceptanceTest extends AbstractJsonRpcTest { private static final String GENESIS_FILE = "/jsonrpc/engine/prague/genesis.json"; private static final String TEST_CASE_PATH = "/jsonrpc/engine/prague/test-cases/"; diff --git a/besu/src/test/java/org/hyperledger/besu/controller/AbstractBftBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/AbstractBftBesuControllerBuilderTest.java index b1cf3dd776d..571f98d4fb5 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/AbstractBftBesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/AbstractBftBesuControllerBuilderTest.java @@ -195,7 +195,6 @@ public void miningParametersBlockPeriodSecondsIsUpdatedOnTransition() { null, null, null, - null, getBlockHeaderFunctions()); final Block block1 = new Block(header1, BlockBody.empty()); diff --git a/besu/src/test/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilderTest.java index b9c919d18f0..284cfa8a832 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilderTest.java @@ -224,7 +224,6 @@ public void miningParametersBlockPeriodSecondsIsUpdatedOnTransition() { null, null, null, - null, new CliqueBlockHeaderFunctions()); final Block block1 = new Block(header1, BlockBody.empty()); diff --git a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java index 79885115f42..453e31378d2 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java @@ -219,7 +219,7 @@ private void setSyncTarget() { mock(EthPeer.class), new org.hyperledger.besu.ethereum.core.BlockHeader( null, null, null, null, null, null, null, null, 1, 1, 1, 1, null, null, null, 1, null, - null, null, null, null, null, null)); + null, null, null, null, null)); } private void clearSyncTarget() { diff --git a/config/src/main/java/org/hyperledger/besu/config/GenesisConfig.java b/config/src/main/java/org/hyperledger/besu/config/GenesisConfig.java index 47fa2967451..43bfd734070 100644 --- a/config/src/main/java/org/hyperledger/besu/config/GenesisConfig.java +++ b/config/src/main/java/org/hyperledger/besu/config/GenesisConfig.java @@ -265,17 +265,6 @@ public String getParentBeaconBlockRoot() { "0x0000000000000000000000000000000000000000000000000000000000000000"); } - /** - * Gets target blobs per block. - * - * @return the target blobs per block - */ - public Optional getTargetBlobsPerBlock() { - // TODO SLD EIP-7742 not sure if we should use a default value here or enforce any - // "pragueAtGenesis" genesis file (used in devnets) to have this value - return JsonUtil.getValueAsString(genesisRoot, "targetblobsperblock"); - } - /** * Gets coinbase. * diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseKey.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseKey.java index d29ca873902..bf5d12804b9 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseKey.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseKey.java @@ -38,6 +38,5 @@ public enum JsonRpcResponseKey { TRANSACTION_ROOT, BASEFEE, WITHDRAWALS_ROOT, - REQUESTS_HASH, - TARGET_BLOBS_PER_BLOCK + REQUESTS_HASH } diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java index 1ef726ae7b8..d72db974b0a 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java @@ -63,7 +63,6 @@ import com.fasterxml.jackson.databind.JsonNode; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; -import org.apache.tuweni.units.bigints.UInt64; public class JsonRpcResponseUtils { @@ -107,10 +106,6 @@ public JsonRpcResponse response( values.containsKey(WITHDRAWALS_ROOT) ? hash(values.get(WITHDRAWALS_ROOT)) : null; final Hash requestsHash = values.containsKey(REQUESTS_HASH) ? hash(values.get(REQUESTS_HASH)) : null; - final UInt64 targetBlobsPerBlock = - values.containsKey(JsonRpcResponseKey.TARGET_BLOBS_PER_BLOCK) - ? UInt64.fromHexString(values.get(JsonRpcResponseKey.TARGET_BLOBS_PER_BLOCK)) - : null; final List ommers = new ArrayList<>(); final BlockHeader header = @@ -136,7 +131,6 @@ public JsonRpcResponse response( null, // ToDo 4844: set with the value of excess_blob_gas field null, // TODO 4788: set with the value of the parent beacon block root field requestsHash, - targetBlobsPerBlock, blockHeaderFunctions); return new JsonRpcSuccessResponse( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java index 0c69c9c1c1d..f3ce31b098e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java @@ -266,7 +266,6 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) : BlobGas.fromHexString(blockParam.getExcessBlobGas()), maybeParentBeaconBlockRoot.orElse(null), maybeRequests.map(BodyValidation::requestsHash).orElse(null), - null, // TODO SLD EIP-7742 wiring in future PR headerFunctions); // ensure the block hash matches the blockParam hash diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java index e74cf2f4e0a..5bfd0ff7b33 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java @@ -88,7 +88,6 @@ public class BlockResult implements JsonRpcResult { private final String blobGasUsed; private final String excessBlobGas; private final String parentBeaconBlockRoot; - private final String targetBlobsPerBlock; private final List callProcessingResults; public BlockResult( @@ -153,7 +152,6 @@ public BlockResult( this.excessBlobGas = header.getExcessBlobGas().map(Quantity::create).orElse(null); this.parentBeaconBlockRoot = header.getParentBeaconBlockRoot().map(Bytes32::toHexString).orElse(null); - this.targetBlobsPerBlock = header.getTargetBlobsPerBlock().map(Quantity::create).orElse(null); } @JsonGetter(value = "number") @@ -292,11 +290,6 @@ public String getParentBeaconBlockRoot() { return parentBeaconBlockRoot; } - @JsonGetter(value = "targetBlobsPerBlock") - public String getTargetBlobsPerBlock() { - return targetBlobsPerBlock; - } - @JsonGetter(value = "calls") public List getTransactionProcessingResults() { return callProcessingResults; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java index c55f9b46547..6f3360821af 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java @@ -372,7 +372,6 @@ private Block createFakeBlock( null, null, null, - null, null), new BlockBody( IntStream.range(0, txsNum) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMaxPriorityFeePerGasTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMaxPriorityFeePerGasTest.java index 05b5f8cb0d7..066f97c0d3f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMaxPriorityFeePerGasTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMaxPriorityFeePerGasTest.java @@ -207,7 +207,6 @@ private Block createFakeBlock( null, null, null, - null, null), new BlockBody( IntStream.range(0, txsNum) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java index 351c973e82d..a230dc5cbaa 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java @@ -254,7 +254,6 @@ private BlockHeader createBlockHeader(final Hash blockHash, final long blockNumb null, null, null, - null, new BlockHeaderFunctions() { @Override public Hash hash(final BlockHeader header) { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java index 7b3d50b2d09..48f98c667a9 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java @@ -120,7 +120,6 @@ public void setup() { null, null, null, - null, new MainnetBlockHeaderFunctions()); testHash = fakeHeader.getHash(); final BlockBody fakeBody = new BlockBody(Collections.emptyList(), Collections.emptyList()); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/cache/TransactionLogBloomCacherTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/cache/TransactionLogBloomCacherTest.java index 293c0b176ea..5772a04a49d 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/cache/TransactionLogBloomCacherTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/cache/TransactionLogBloomCacherTest.java @@ -108,7 +108,6 @@ public void setup() throws IOException { null, null, null, - null, new MainnetBlockHeaderFunctions()); testHash = fakeHeader.getHash(); when(blockchain.getBlockHeader(anyLong())).thenReturn(Optional.of(fakeHeader)); @@ -284,7 +283,6 @@ private BlockHeader createBlock(final long number, final Optional messag null, null, null, - null, new MainnetBlockHeaderFunctions()); testHash = fakeHeader.getHash(); when(blockchain.getBlockHeader(number)).thenReturn(Optional.of(fakeHeader)); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java index 56c33e55c7d..e770fe97520 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java @@ -48,7 +48,6 @@ import com.google.common.base.MoreObjects; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.units.bigints.UInt64; public final class GenesisState { @@ -217,12 +216,6 @@ private static BlockHeader buildHeader( .parentBeaconBlockRoot( (isCancunAtGenesis(genesis) ? parseParentBeaconBlockRoot(genesis) : null)) .requestsHash(isPragueAtGenesis(genesis) ? Hash.EMPTY_REQUESTS_HASH : null) - .targetBlobsPerBlock( - isPragueAtGenesis(genesis) - // TODO SLD EIP-7742 Currently defaulting to null due to dependency on web3j - // BlockHeader in CodeDelegationTransactionAcceptanceTest - ? genesis.getTargetBlobsPerBlock().map(UInt64::fromHexString).orElse(null) - : null) .buildBlockHeader(); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java index e41e0823bc8..6bd1a2aa588 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java @@ -28,7 +28,6 @@ import com.google.common.base.Suppliers; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.units.bigints.UInt64; /** A mined Ethereum block header. */ public class BlockHeader extends SealableBlockHeader @@ -66,7 +65,6 @@ public BlockHeader( final BlobGas excessBlobGas, final Bytes32 parentBeaconBlockRoot, final Hash requestsHash, - final UInt64 targetBlobsPerBlock, final BlockHeaderFunctions blockHeaderFunctions) { super( parentHash, @@ -88,8 +86,7 @@ public BlockHeader( blobGasUsed, excessBlobGas, parentBeaconBlockRoot, - requestsHash, - targetBlobsPerBlock); + requestsHash); this.nonce = nonce; this.hash = Suppliers.memoize(() -> blockHeaderFunctions.hash(this)); this.parsedExtraData = Suppliers.memoize(() -> blockHeaderFunctions.parseExtraData(this)); @@ -190,9 +187,6 @@ public void writeTo(final RLPOutput out) { if (requestsHash == null) break; out.writeBytes(requestsHash); - - if (targetBlobsPerBlock == null) break; - out.writeUInt64Scalar(targetBlobsPerBlock); } while (false); out.endList(); } @@ -225,8 +219,6 @@ public static BlockHeader readFrom( !input.isEndOfCurrentList() ? BlobGas.of(input.readUInt64Scalar()) : null; final Bytes32 parentBeaconBlockRoot = !input.isEndOfCurrentList() ? input.readBytes32() : null; final Hash requestsHash = !input.isEndOfCurrentList() ? Hash.wrap(input.readBytes32()) : null; - final UInt64 targetBlobsPerBlock = - !input.isEndOfCurrentList() ? input.readUInt64Scalar() : null; input.leaveList(); return new BlockHeader( parentHash, @@ -250,7 +242,6 @@ public static BlockHeader readFrom( excessBlobGas, parentBeaconBlockRoot, requestsHash, - targetBlobsPerBlock, blockHeaderFunctions); } @@ -304,9 +295,6 @@ public String toString() { if (requestsHash != null) { sb.append("requestsHash=").append(requestsHash); } - if (targetBlobsPerBlock != null) { - sb.append("targetBlobsPerBlock=").append(targetBlobsPerBlock); - } return sb.append("}").toString(); } @@ -341,7 +329,6 @@ public static org.hyperledger.besu.ethereum.core.BlockHeader convertPluginBlockH .getRequestsHash() .map(h -> Hash.fromHexString(h.toHexString())) .orElse(null), - pluginBlockHeader.getTargetBlobsPerBlock().orElse(null), blockHeaderFunctions); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java index 381785995ac..550f6c18887 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java @@ -34,7 +34,6 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.units.bigints.UInt64; /** A utility class for building block headers. */ public class BlockHeaderBuilder { @@ -81,7 +80,6 @@ public class BlockHeaderBuilder { private Long blobGasUsed = null; private BlobGas excessBlobGas = null; private Bytes32 parentBeaconBlockRoot = null; - private UInt64 targetBlobsPerBlock = null; public static BlockHeaderBuilder create() { return new BlockHeaderBuilder(); @@ -130,8 +128,7 @@ public static BlockHeaderBuilder fromHeader(final BlockHeader header) { .blobGasUsed(header.getBlobGasUsed().orElse(null)) .excessBlobGas(header.getExcessBlobGas().orElse(null)) .parentBeaconBlockRoot(header.getParentBeaconBlockRoot().orElse(null)) - .requestsHash(header.getRequestsHash().orElse(null)) - .targetBlobsPerBlock(header.getTargetBlobsPerBlock().orElse(null)); + .requestsHash(header.getRequestsHash().orElse(null)); } public static BlockHeaderBuilder fromBuilder(final BlockHeaderBuilder fromBuilder) { @@ -156,7 +153,6 @@ public static BlockHeaderBuilder fromBuilder(final BlockHeaderBuilder fromBuilde .excessBlobGas(fromBuilder.excessBlobGas) .parentBeaconBlockRoot(fromBuilder.parentBeaconBlockRoot) .requestsHash(fromBuilder.requestsHash) - .targetBlobsPerBlock(fromBuilder.targetBlobsPerBlock) .blockHeaderFunctions(fromBuilder.blockHeaderFunctions); toBuilder.nonce = fromBuilder.nonce; return toBuilder; @@ -236,7 +232,6 @@ public BlockHeader buildBlockHeader() { excessBlobGas, parentBeaconBlockRoot, requestsHash, - targetBlobsPerBlock, blockHeaderFunctions); } @@ -252,8 +247,7 @@ public ProcessableBlockHeader buildProcessableBlockHeader() { timestamp, baseFee, mixHashOrPrevRandao, - parentBeaconBlockRoot, - targetBlobsPerBlock); + parentBeaconBlockRoot); } public SealableBlockHeader buildSealableBlockHeader() { @@ -279,8 +273,7 @@ public SealableBlockHeader buildSealableBlockHeader() { blobGasUsed, excessBlobGas, parentBeaconBlockRoot, - requestsHash, - targetBlobsPerBlock); + requestsHash); } private void validateBlockHeader() { @@ -320,7 +313,6 @@ public BlockHeaderBuilder populateFrom(final ProcessableBlockHeader processableB baseFee(processableBlockHeader.getBaseFee().orElse(null)); processableBlockHeader.getPrevRandao().ifPresent(this::prevRandao); processableBlockHeader.getParentBeaconBlockRoot().ifPresent(this::parentBeaconBlockRoot); - processableBlockHeader.getTargetBlobsPerBlock().ifPresent(this::targetBlobsPerBlock); return this; } @@ -346,7 +338,6 @@ public BlockHeaderBuilder populateFrom(final SealableBlockHeader sealableBlockHe sealableBlockHeader.getExcessBlobGas().ifPresent(this::excessBlobGas); sealableBlockHeader.getParentBeaconBlockRoot().ifPresent(this::parentBeaconBlockRoot); requestsHash(sealableBlockHeader.getRequestsHash().orElse(null)); - sealableBlockHeader.getTargetBlobsPerBlock().ifPresent(this::targetBlobsPerBlock); return this; } @@ -480,9 +471,4 @@ public BlockHeaderBuilder parentBeaconBlockRoot(final Bytes32 parentBeaconBlockR this.parentBeaconBlockRoot = parentBeaconBlockRoot; return this; } - - public BlockHeaderBuilder targetBlobsPerBlock(final UInt64 targetBlobsPerBlock) { - this.targetBlobsPerBlock = targetBlobsPerBlock; - return this; - } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java index 20650bc74aa..0af72a1c83f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java @@ -23,7 +23,6 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.units.bigints.UInt64; /** A block header capable of being processed. */ public class ProcessableBlockHeader @@ -47,8 +46,6 @@ public class ProcessableBlockHeader protected final Bytes32 mixHashOrPrevRandao; // parentBeaconBlockRoot is included for Cancun protected final Bytes32 parentBeaconBlockRoot; - // TODO SLD Quantity or UInt64Value instead? - protected final UInt64 targetBlobsPerBlock; protected ProcessableBlockHeader( final Hash parentHash, @@ -59,8 +56,7 @@ protected ProcessableBlockHeader( final long timestamp, final Wei baseFee, final Bytes32 mixHashOrPrevRandao, - final Bytes32 parentBeaconBlockRoot, - final UInt64 targetBlobsPerBlock) { + final Bytes32 parentBeaconBlockRoot) { this.parentHash = parentHash; this.coinbase = coinbase; this.difficulty = difficulty; @@ -70,7 +66,6 @@ protected ProcessableBlockHeader( this.baseFee = baseFee; this.mixHashOrPrevRandao = mixHashOrPrevRandao; this.parentBeaconBlockRoot = parentBeaconBlockRoot; - this.targetBlobsPerBlock = targetBlobsPerBlock; } /** @@ -183,16 +178,6 @@ public Optional getParentBeaconBlockRoot() { return Optional.ofNullable(parentBeaconBlockRoot); } - /** - * Returns the target blobs per block if available. - * - * @return the target blobs per block if available. - */ - @Override - public Optional getTargetBlobsPerBlock() { - return Optional.ofNullable(targetBlobsPerBlock); - } - public String toLogString() { return getNumber() + " (time: " + getTimestamp() + ")"; } @@ -212,9 +197,6 @@ public String toString() { if (parentBeaconBlockRoot != null) { sb.append("parentBeaconBlockRoot=").append(parentBeaconBlockRoot).append(", "); } - if (targetBlobsPerBlock != null) { - sb.append("targetBlobsPerBlock=").append(targetBlobsPerBlock); - } return sb.append("}").toString(); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java index 40d25f9e2a7..1934c8f8c0e 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java @@ -24,7 +24,6 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.units.bigints.UInt64; /** A block header capable of being sealed. */ public class SealableBlockHeader extends ProcessableBlockHeader { @@ -70,8 +69,7 @@ protected SealableBlockHeader( final Long blobGasUsed, final BlobGas excessBlobGas, final Bytes32 parentBeaconBlockRoot, - final Hash requestsHash, - final UInt64 targetBlobsPerBlock) { + final Hash requestsHash) { super( parentHash, coinbase, @@ -81,8 +79,7 @@ protected SealableBlockHeader( timestamp, baseFee, mixHashOrPrevRandao, - parentBeaconBlockRoot, - targetBlobsPerBlock); + parentBeaconBlockRoot); this.ommersHash = ommersHash; this.stateRoot = stateRoot; this.transactionsRoot = transactionsRoot; diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockHeaderTestFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockHeaderTestFixture.java index 825cdec29b2..99cf2407b8d 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockHeaderTestFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockHeaderTestFixture.java @@ -25,7 +25,6 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.units.bigints.UInt64; public class BlockHeaderTestFixture { @@ -56,7 +55,6 @@ public class BlockHeaderTestFixture { private Optional excessBlobGas = Optional.empty(); private Optional blobGasUsed = Optional.empty(); private Optional parentBeaconBlockRoot = Optional.empty(); - private Optional targetBlobsPerBlock = Optional.empty(); public BlockHeader buildHeader() { final BlockHeaderBuilder builder = BlockHeaderBuilder.create(); @@ -82,7 +80,6 @@ public BlockHeader buildHeader() { blobGasUsed.ifPresent(builder::blobGasUsed); requestsHash.ifPresent(builder::requestsHash); parentBeaconBlockRoot.ifPresent(builder::parentBeaconBlockRoot); - targetBlobsPerBlock.ifPresent(builder::targetBlobsPerBlock); builder.blockHeaderFunctions(blockHeaderFunctions); return builder.buildBlockHeader(); @@ -204,9 +201,4 @@ public BlockHeaderTestFixture parentBeaconBlockRoot( this.parentBeaconBlockRoot = parentBeaconBlockRoot; return this; } - - public BlockHeaderTestFixture targetBlobsPerBlock(final UInt64 targetBlobsPerBlock) { - this.targetBlobsPerBlock = Optional.of(targetBlobsPerBlock); - return this; - } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/GenesisStateTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/GenesisStateTest.java index a4584cc938a..ba036347085 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/GenesisStateTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/GenesisStateTest.java @@ -31,7 +31,6 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; -import org.apache.tuweni.units.bigints.UInt64; import org.bouncycastle.util.encoders.Hex; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtensionContext; @@ -288,6 +287,10 @@ void genesisFromPrague(final DataStorageConfiguration dataStorageConfiguration) GenesisStateTest.class.getResource("genesis_prague.json"), ProtocolScheduleFixture.MAINNET); final BlockHeader header = genesisState.getBlock().getHeader(); + assertThat(header.getHash()) + .isEqualTo( + Hash.fromHexString( + "0x554807b22674e6d335f734485993857bbad7a9543affb0663a10c14d78135ec7")); assertThat(header.getGasLimit()).isEqualTo(0x2fefd8); assertThat(header.getGasUsed()).isZero(); assertThat(header.getNumber()).isZero(); @@ -328,13 +331,6 @@ void genesisFromPrague(final DataStorageConfiguration dataStorageConfiguration) .isEqualTo( Hash.fromHexString( "0x6036c41849da9c076ed79654d434017387a88fb833c2856b32e18218b3341c5f")); - assertThat(header.getTargetBlobsPerBlock().isPresent()).isTrue(); - assertThat(header.getTargetBlobsPerBlock().get()).isEqualTo(UInt64.ONE); - - assertThat(header.getHash()) - .isEqualTo( - Hash.fromHexString( - "0xdbc64edecb3a432e48cbd270b4a248ffc611b5f3dd666c8a10d546672cae17bd")); } @Test diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/LogRollingTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/LogRollingTests.java index 6a70cb20e28..e43d464474c 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/LogRollingTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/LogRollingTests.java @@ -99,7 +99,6 @@ class LogRollingTests { null, null, null, - null, new MainnetBlockHeaderFunctions()); private static final BlockHeader headerTwo = new BlockHeader( @@ -124,7 +123,6 @@ class LogRollingTests { null, null, null, - null, new MainnetBlockHeaderFunctions()); @BeforeEach diff --git a/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_prague.json b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_prague.json index 10cf0191824..d99071b328d 100644 --- a/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_prague.json +++ b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_prague.json @@ -4073,6 +4073,5 @@ "number": "0x0", "gasUsed": "0x0", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "baseFeePerGas": "0x3b9aca00", - "targetBlobsPerBlock": "0x1" + "baseFeePerGas": "0x3b9aca00" } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/MessageWrapperTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/MessageWrapperTest.java index 0256b096532..2b020cd4ac8 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/MessageWrapperTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/MessageWrapperTest.java @@ -398,7 +398,6 @@ public TestBlockHeader( null, null, null, - null, new MainnetBlockHeaderFunctions()); } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ChainForTestCreator.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ChainForTestCreator.java index 109a66e2c1a..c15f3aa1dcd 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ChainForTestCreator.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ChainForTestCreator.java @@ -61,7 +61,6 @@ public static BlockHeader prepareHeader(final long number, final Optional getBaseFee() { */ @Unstable Optional getParentBeaconBlockRoot(); - - /** - * The target_blobs_per_block of this header. - * - * @return The target blobs per block of this header. - */ - @Unstable - // TODO SLD should be Quantity or new subclass of Quantity? - default Optional getTargetBlobsPerBlock() { - return Optional.empty(); - } } From 01126c0853e5a1152e760b4a5d1aa3862301e1c8 Mon Sep 17 00:00:00 2001 From: Usman Saleem Date: Tue, 7 Jan 2025 13:14:39 +1000 Subject: [PATCH 2/4] Reimplement EthereumNodeRecord for DNS discovery (#7989) * Reimplement EthereumNodeRecord and remove dependency on tuweni-devp2p * Refactor EthereumNodeRecord for DNSDaemon * Update EthereumNodeRecord to use Besu RLP * additional unit tests * Convert ENR to Java record * regenerate equals and hashcode for enr record --------- Signed-off-by: Usman Saleem --- .../besu/crypto/AbstractSECP256.java | 5 + .../besu/crypto/SignatureAlgorithm.java | 8 + ethereum/p2p/build.gradle | 3 - .../ethereum/p2p/discovery/dns/DNSDaemon.java | 1 - .../p2p/discovery/dns/DNSDaemonListener.java | 2 - .../ethereum/p2p/discovery/dns/DNSEntry.java | 1 - .../p2p/discovery/dns/DNSResolver.java | 1 - .../p2p/discovery/dns/DNSVisitor.java | 2 - .../p2p/discovery/dns/EthereumNodeRecord.java | 154 ++++++++++++++++++ .../p2p/network/DefaultP2PNetwork.java | 8 +- .../p2p/discovery/dns/DNSDaemonTest.java | 18 +- .../discovery/dns/EthereumNodeRecordTest.java | 56 +++++++ gradle/verification-metadata.xml | 8 - platform/build.gradle | 1 - 14 files changed, 244 insertions(+), 24 deletions(-) create mode 100644 ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/EthereumNodeRecord.java create mode 100644 ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/EthereumNodeRecordTest.java 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 4e228441cc4..2098dfeadc1 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 @@ -233,6 +233,11 @@ public String getProvider() { return PROVIDER; } + @Override + public ECDomainParameters getCurve() { + return curve; + } + /** * Gets K calculator. * 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 a1a79d057a5..1d077d51d26 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 @@ -20,6 +20,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; +import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.math.ec.ECPoint; /** The interface Signature algorithm. */ @@ -124,6 +125,13 @@ SECPSignature normaliseSignature( */ String getCurveName(); + /** + * Bouncy castle ECDomainParameters representing the curve. + * + * @return instance of ECDomainParameters + */ + ECDomainParameters getCurve(); + /** * Create secp private key. * diff --git a/ethereum/p2p/build.gradle b/ethereum/p2p/build.gradle index 6ed42425e0a..f4eb5066284 100644 --- a/ethereum/p2p/build.gradle +++ b/ethereum/p2p/build.gradle @@ -46,9 +46,6 @@ dependencies { implementation 'io.tmio:tuweni-bytes' implementation 'io.tmio:tuweni-crypto' - implementation('io.tmio:tuweni-devp2p') { - exclude group:'ch.qos.logback', module:'logback-classic' - } implementation 'io.tmio:tuweni-io' implementation 'io.tmio:tuweni-rlp' implementation 'io.tmio:tuweni-units' diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSDaemon.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSDaemon.java index ef794ae2047..7c2d9350f62 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSDaemon.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSDaemon.java @@ -18,7 +18,6 @@ import java.util.Optional; import io.vertx.core.AbstractVerticle; -import org.apache.tuweni.devp2p.EthereumNodeRecord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSDaemonListener.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSDaemonListener.java index cfa51d4eb73..81629268a8a 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSDaemonListener.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSDaemonListener.java @@ -16,8 +16,6 @@ import java.util.List; -import org.apache.tuweni.devp2p.EthereumNodeRecord; - // Adapted from https://github.com/tmio/tuweni and licensed under Apache 2.0 /** Callback listening to updates of the DNS records. */ @FunctionalInterface diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSEntry.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSEntry.java index cd439eea063..810bd3b41b1 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSEntry.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSEntry.java @@ -25,7 +25,6 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.crypto.SECP256K1; -import org.apache.tuweni.devp2p.EthereumNodeRecord; import org.apache.tuweni.io.Base32; import org.apache.tuweni.io.Base64URLSafe; import org.bouncycastle.math.ec.ECPoint; diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSResolver.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSResolver.java index 0be4ca619d1..c3347aa8d9e 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSResolver.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSResolver.java @@ -33,7 +33,6 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.crypto.SECP256K1; -import org.apache.tuweni.devp2p.EthereumNodeRecord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSVisitor.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSVisitor.java index c6ea0a77ed7..fc9b5af9965 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSVisitor.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSVisitor.java @@ -14,8 +14,6 @@ */ package org.hyperledger.besu.ethereum.p2p.discovery.dns; -import org.apache.tuweni.devp2p.EthereumNodeRecord; - // Adapted from https://github.com/tmio/tuweni and licensed under Apache 2.0 /** * Reads ENR (Ethereum Node Records) entries passed in from DNS. The visitor may decide to stop the diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/EthereumNodeRecord.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/EthereumNodeRecord.java new file mode 100644 index 00000000000..339afcffca3 --- /dev/null +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/EthereumNodeRecord.java @@ -0,0 +1,154 @@ +/* + * 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 + */ + +// Adapted from https://github.com/tmio/tuweni and licensed under Apache 2.0 +package org.hyperledger.besu.ethereum.p2p.discovery.dns; + +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; + +import java.net.InetAddress; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes; + +/** + * A modified implementation of Ethereum Node Record (ENR) that is used by DNSResolver. See EIP-778 + */ +public record EthereumNodeRecord( + Bytes rlp, Bytes publicKey, InetAddress ip, Optional tcp, Optional udp) { + + /** + * Creates an ENR from its serialized form as a RLP list + * + * @param rlp the serialized form of the ENR + * @return the ENR + * @throws IllegalArgumentException if the rlp bytes length is longer than 300 bytes + */ + public static EthereumNodeRecord fromRLP(final Bytes rlp) { + if (rlp.size() > 300) { + throw new IllegalArgumentException("Record too long"); + } + var data = new HashMap(); + + // rlp: sig, sequence, k1,v1, k2,v2, k3, [v3, vn]... + var input = new BytesValueRLPInput(rlp, false); + input.enterList(); + + input.skipNext(); // skip signature + input.skipNext(); // skip sequence + + // go through rest of the list + while (!input.isEndOfCurrentList()) { + var key = new String(input.readBytes().toArrayUnsafe(), StandardCharsets.UTF_8); + if (input.nextIsList()) { + // skip list as we currently don't need any of these complex structures + input.skipNext(); + } else { + data.put(key, input.readBytes()); + } + } + + input.leaveList(); + + var publicKey = initPublicKeyBytes(data); + + return new EthereumNodeRecord(rlp, publicKey, initIPAddr(data), initTCP(data), initUDP(data)); + } + + /** + * Returns the public key of the ENR + * + * @return the public key of the ENR + */ + static Bytes initPublicKeyBytes(final Map data) { + var keyBytes = data.get("secp256k1"); + if (keyBytes == null) { + throw new IllegalArgumentException("Missing secp256k1 entry in ENR"); + } + // convert 33 bytes compressed public key to uncompressed using Bouncy Castle + var curve = SignatureAlgorithmFactory.getInstance().getCurve(); + var ecPoint = curve.getCurve().decodePoint(keyBytes.toArrayUnsafe()); + // uncompressed public key is 65 bytes, first byte is 0x04. + var encodedPubKey = ecPoint.getEncoded(false); + return Bytes.of(Arrays.copyOfRange(encodedPubKey, 1, encodedPubKey.length)); + } + + /** + * Returns the InetAddress of the ENR + * + * @return The IP address of the ENR + */ + static InetAddress initIPAddr(final Map data) { + var ipBytes = data.get("ip"); + if (ipBytes != null) { + try { + return InetAddress.getByAddress(ipBytes.toArrayUnsafe()); + } catch (final Exception e) { + throw new RuntimeException(e); + } + } + return InetAddress.getLoopbackAddress(); + } + + /** + * The TCP port of the ENR + * + * @return the TCP port associated with this ENR + */ + static Optional initTCP(final Map data) { + var tcpBytes = data.get("tcp"); + return tcpBytes != null ? Optional.of(tcpBytes.toInt()) : Optional.empty(); + } + + /** + * The UDP port of the ENR. If the UDP port is not present, the TCP port is used. + * + * @return the UDP port associated with this ENR + */ + static Optional initUDP(final Map data) { + var udpBytes = data.get("udp"); + return udpBytes != null ? Optional.of(udpBytes.toInt()) : initTCP(data); + } + + /** + * @return the ENR as a URI + */ + @Override + public String toString() { + return "enr:" + ip() + ":" + tcp() + "?udp=" + udp(); + } + + /** Override equals method to compare the RLP bytes */ + @Override + public boolean equals(final Object o) { + if (!(o instanceof EthereumNodeRecord that)) { + return false; + } + return Objects.equals(rlp, that.rlp); + } + + /** Override hashCode method to use hashCode of the RLP bytes */ + @Override + public int hashCode() { + return Objects.hashCode(rlp); + } +} diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java index 610ebd39d8a..bf8e76b6215 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.p2p.discovery.VertxPeerDiscoveryAgent; import org.hyperledger.besu.ethereum.p2p.discovery.dns.DNSDaemon; import org.hyperledger.besu.ethereum.p2p.discovery.dns.DNSDaemonListener; +import org.hyperledger.besu.ethereum.p2p.discovery.dns.EthereumNodeRecord; import org.hyperledger.besu.ethereum.p2p.discovery.internal.PeerTable; import org.hyperledger.besu.ethereum.p2p.peers.DefaultPeerPrivileges; import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl; @@ -82,7 +83,6 @@ import io.vertx.core.ThreadingModel; import io.vertx.core.Vertx; import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.devp2p.EthereumNodeRecord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -366,9 +366,9 @@ DNSDaemonListener createDaemonListener() { final EnodeURL enodeURL = EnodeURLImpl.builder() .ipAddress(enr.ip()) - .nodeId(enr.publicKey().bytes()) - .discoveryPort(Optional.ofNullable(enr.udp())) - .listeningPort(Optional.ofNullable(enr.tcp())) + .nodeId(enr.publicKey()) + .discoveryPort(enr.udp()) + .listeningPort(enr.tcp()) .build(); final DiscoveryPeer peer = DiscoveryPeer.fromEnode(enodeURL); peers.add(peer); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSDaemonTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSDaemonTest.java index 94d9c75e4ae..b25148126c4 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSDaemonTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSDaemonTest.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.ethereum.p2p.discovery.dns; +import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl; + import java.security.Security; import java.util.concurrent.atomic.AtomicInteger; @@ -67,10 +69,24 @@ void testDNSDaemon(final Vertx vertx, final VertxTestContext testContext) { testContext.failNow( "Expecting 115 records in first pass but got: " + records.size()); } + records.forEach( + enr -> { + try { + // make sure enode url can be built from record + EnodeURLImpl.builder() + .ipAddress(enr.ip()) + .nodeId(enr.publicKey()) + .discoveryPort(enr.udp()) + .listeningPort(enr.tcp()) + .build(); + } catch (final Exception e) { + testContext.failNow(e); + } + }); checkpoint.flag(); }, 0, - 0, + 1L, 0, "localhost:" + mockDnsServerVerticle.port()); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/EthereumNodeRecordTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/EthereumNodeRecordTest.java new file mode 100644 index 00000000000..da5cfd0f31c --- /dev/null +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/EthereumNodeRecordTest.java @@ -0,0 +1,56 @@ +/* + * Copyright contributors to 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.p2p.discovery.dns; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.net.InetAddress; +import java.util.Random; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.Test; + +class EthereumNodeRecordTest { + + @Test + void buildFromRLP() throws Exception { + final Bytes rlp = + Bytes.fromHexString( + "0xf8a3b84033b8a07e5c8e19dc8ac2529354b21a6c09e5516335eb57c383924aa0ca73434c0c65d8625eb05236e172fcc00d80e913506bde5446fb5c55ea2035380c97480a86018d56dc241083657468c7c6849b192ad0808269648276348269708441157e4389736563703235366b31a102a48c4c032f4c2e1b4007dd15b0d7046b60774f6bc38e2f52a8e0361c65e4234284736e6170c08374637082765f8375647082765f"); + // method under test + final EthereumNodeRecord enr = EthereumNodeRecord.fromRLP(rlp); + // expected values + final InetAddress expectedIPAddr = + InetAddress.getByAddress(Bytes.fromHexString("0x41157e43").toArrayUnsafe()); + final Bytes expectedPublicKey = + Bytes.fromHexString( + "0xa48c4c032f4c2e1b4007dd15b0d7046b60774f6bc38e2f52a8e0361c65e423424520b07898c59a8c9e85c440594ca734f23b7f2b906d5da54676eee6a1d64874"); + + // assertions + assertThat(enr.ip()).isEqualTo(expectedIPAddr); + assertThat(enr.publicKey()).isEqualTo(expectedPublicKey); + assertThat(enr.tcp()).isNotEmpty().contains(30303); + assertThat(enr.udp()).isNotEmpty().contains(30303); + } + + @Test + void buildFromRLPWithSizeGreaterThan300() { + final Bytes rlp = Bytes.random(301, new Random(1L)); + assertThatThrownBy(() -> EthereumNodeRecord.fromRLP(rlp)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Record too long"); + } +} diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index c3acee03312..1a36b557aa2 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -2883,14 +2883,6 @@ - - - - - - - - diff --git a/platform/build.gradle b/platform/build.gradle index f5bb54afcd1..cffc33659ff 100644 --- a/platform/build.gradle +++ b/platform/build.gradle @@ -110,7 +110,6 @@ dependencies { api 'io.tmio:tuweni-config:2.4.2' api 'io.tmio:tuweni-concurrent:2.4.2' api 'io.tmio:tuweni-crypto:2.4.2' - api 'io.tmio:tuweni-devp2p:2.4.2' api 'io.tmio:tuweni-io:2.4.2' api 'io.tmio:tuweni-net:2.4.2' api 'io.tmio:tuweni-rlp:2.4.2' From fa9ca9c27f18799c09a740057ee934dd07e266d9 Mon Sep 17 00:00:00 2001 From: Simon Dudley Date: Tue, 7 Jan 2025 16:25:02 +1000 Subject: [PATCH 3/4] Update EIP-2935 (#8066) * Update HISTORY_STORAGE_ADDRESS and HISTORY_SERVE_WINDOW for EIP-2935 https://github.com/hyperledger/besu/issues/8061 * Update HISTORY_STORAGE_ADDRESS and genesis code in tests. Even for unrelated tests, this has a knock-on impact on the state root due to the history storage account being created when the BlockHashProcessor runs for block 1 Signed-off-by: Simon Dudley --- .../ExecutionEnginePragueAcceptanceTest.java | 3 ++ .../debug_traceCall_noGasPrice.json | 2 +- .../blockhash/PragueBlockHashProcessor.java | 4 +-- .../besu/ethereum/chain/genesis_prague2.json | 4 +-- .../evmtool/block-test/osaka-eof-rjump.json | 30 +++++++++---------- .../besu/evmtool/t8n/prague-deposit.json | 10 +++---- .../t8n/prague-withdrawal-request.json | 10 +++---- 7 files changed, 33 insertions(+), 30 deletions(-) diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEnginePragueAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEnginePragueAcceptanceTest.java index 966c02bebde..f38a192d4df 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEnginePragueAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEnginePragueAcceptanceTest.java @@ -20,8 +20,11 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.params.provider.Arguments; +// TODO SLD +@Disabled("TODO SLD - Enable when Prague spec is finalized") public class ExecutionEnginePragueAcceptanceTest extends AbstractJsonRpcTest { private static final String GENESIS_FILE = "/jsonrpc/engine/prague/genesis.json"; private static final String TEST_CASE_PATH = "/jsonrpc/engine/prague/test-cases/"; diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-call/debug_traceCall_noGasPrice.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-call/debug_traceCall_noGasPrice.json index 18fe53baa16..b19651cb016 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-call/debug_traceCall_noGasPrice.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-call/debug_traceCall_noGasPrice.json @@ -4,7 +4,7 @@ "method": "debug_traceCall", "params": [ { - "to": "0x0aae40965e6800cd9b1f4b05ff21581047e3f91e", + "to": "0x0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC", "data": "0x000000000000000000000000000000000000000000000000000000000001A00E" }, "latest", diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockhash/PragueBlockHashProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockhash/PragueBlockHashProcessor.java index 62e2dc7c99d..5b772f1cd63 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockhash/PragueBlockHashProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockhash/PragueBlockHashProcessor.java @@ -35,10 +35,10 @@ public class PragueBlockHashProcessor extends CancunBlockHashProcessor { private static final Logger LOG = LoggerFactory.getLogger(PragueBlockHashProcessor.class); public static final Address HISTORY_STORAGE_ADDRESS = - Address.fromHexString("0x0aae40965e6800cd9b1f4b05ff21581047e3f91e"); + Address.fromHexString("0x0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC"); /** The HISTORY_SERVE_WINDOW */ - private static final long HISTORY_SERVE_WINDOW = 8192; + private static final long HISTORY_SERVE_WINDOW = 8191; protected final long historyServeWindow; protected final Address historyStorageAddress; diff --git a/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_prague2.json b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_prague2.json index cdb755ace18..0f0485c983a 100644 --- a/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_prague2.json +++ b/ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_prague2.json @@ -73,8 +73,8 @@ "balance": "0x0", "nonce": "0x1" }, - "0x0aae40965e6800cd9b1f4b05ff21581047e3f91e": { - "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500", + "0x0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC": { + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", "balance": "0x0", "nonce": "0x1" }, diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/block-test/osaka-eof-rjump.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/block-test/osaka-eof-rjump.json index a6c5bcc62c3..b70da91fc9e 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/block-test/osaka-eof-rjump.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/block-test/osaka-eof-rjump.json @@ -4,13 +4,13 @@ "stdin" ], "stdin": { - "tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]": { + "tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]": { "network": "Osaka", "genesisBlockHeader": { "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "coinbase": "0x0000000000000000000000000000000000000000", - "stateRoot": "0xbeb30acb62768b375f7e7d36f6ba9240cb692ebd0ee04c9321c756cf4ff1c437", + "stateRoot": "0x6cb1761e069313d13f39d755da011dc921b1f0fe5c4c3e951891639e479b4cfb", "transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", @@ -28,7 +28,7 @@ "excessBlobGas": "0x00", "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "requestsHash": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "hash": "0x367310df4a31070aa9a5c92cb61ab8bb2742db0162619ed77594fbec6f0ddbd9" + "hash": "0x67315ef3267f6f654068ccbd317423b1028fd5305b94a56d1f27e6651e06d678" }, "pre": { "0x00000000219ab540356cbb839cbe05303d7705fa": { @@ -81,10 +81,10 @@ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe146098573615156028575f545f5260205ff35b36606014156101445760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061014457600154600101600155600354806004026004013381556001015f35815560010160203581556001016040359055600101600355005b6003546002548082038060011160ac575060015b5f5b81811460f15780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160ae565b9101809214610103579060025561010e565b90505f6002555f6003555b5f548061049d141561011d57505f5b6001546001828201116101325750505f610138565b01600190035b5f555f6001556074025ff35b5f5ffd", "storage": {} }, - "0x0aae40965e6800cd9b1f4b05ff21581047e3f91e": { + "0x0f792be4b0c0cb4dae440ef133e90c0ecd48cccc": { "nonce": "0x01", "balance": "0x00", - "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", "storage": {} }, "0x000f3df6d732807ef1319fb7b8bb8522d0beac02": { @@ -173,12 +173,12 @@ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe146098573615156028575f545f5260205ff35b36606014156101445760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061014457600154600101600155600354806004026004013381556001015f35815560010160203581556001016040359055600101600355005b6003546002548082038060011160ac575060015b5f5b81811460f15780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160ae565b9101809214610103579060025561010e565b90505f6002555f6003555b5f548061049d141561011d57505f5b6001546001828201116101325750505f610138565b01600190035b5f555f6001556074025ff35b5f5ffd", "storage": {} }, - "0x0aae40965e6800cd9b1f4b05ff21581047e3f91e": { + "0x0f792be4b0c0cb4dae440ef133e90c0ecd48cccc": { "nonce": "0x01", "balance": "0x00", - "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", "storage": { - "0x00": "0x367310df4a31070aa9a5c92cb61ab8bb2742db0162619ed77594fbec6f0ddbd9" + "0x00": "0x67315ef3267f6f654068ccbd317423b1028fd5305b94a56d1f27e6651e06d678" } }, "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { @@ -194,15 +194,15 @@ "storage": {} } }, - "lastblockhash": "0xfb5d1d0e218fa7873bc188f07f3e0a7c78027ff6e6e199c48ba1facd3c3726fd", - "genesisRLP": "0xf90262f9025ba00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0beb30acb62768b375f7e7d36f6ba9240cb692ebd0ee04c9321c756cf4ff1c437a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808088016345785d8a0000808000a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421c0c0c0c0", + "lastblockhash": "0x9ca58820df28ca6d09450fff5fdf93d39976e3aa098c6981ae08f391d44ffb3f", + "genesisRLP": "0xf90262f9025ba00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a06cb1761e069313d13f39d755da011dc921b1f0fe5c4c3e951891639e479b4cfba056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808088016345785d8a0000808000a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421c0c0c0c0", "blocks": [ { "blockHeader": { - "parentHash": "0x367310df4a31070aa9a5c92cb61ab8bb2742db0162619ed77594fbec6f0ddbd9", + "parentHash": "0x67315ef3267f6f654068ccbd317423b1028fd5305b94a56d1f27e6651e06d678", "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "coinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "stateRoot": "0x4ab70cbe1abe50d6bb3c8cdb3e9e66111f142cd68ab73870e9ce9e0dd1d6ead2", + "stateRoot": "0x61171b085ffd8d099ca59ba13164e8883d89c89d3298256aa229b03a6e33d246", "transactionsTrie": "0xec9d10cff79619f2df45db8c66526ef3fbd32d283fdd2dcc9b55c0efe643d8c3", "receiptTrie": "0x9593f56abf23bcbb26d27b0c6e46a56415d9103ed6b4d8ac7b4182f9f250cafa", "bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", @@ -220,7 +220,7 @@ "excessBlobGas": "0x00", "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "requestsHash": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "hash": "0xfb5d1d0e218fa7873bc188f07f3e0a7c78027ff6e6e199c48ba1facd3c3726fd" + "hash": "0x9ca58820df28ca6d09450fff5fdf93d39976e3aa098c6981ae08f391d44ffb3f" }, "transactions": [ { @@ -243,7 +243,7 @@ "depositRequests": [], "withdrawalRequests": [], "consolidationRequests": [], - "rlp": "0xf902c9f9025fa0367310df4a31070aa9a5c92cb61ab8bb2742db0162619ed77594fbec6f0ddbd9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa04ab70cbe1abe50d6bb3c8cdb3e9e66111f142cd68ab73870e9ce9e0dd1d6ead2a0ec9d10cff79619f2df45db8c66526ef3fbd32d283fdd2dcc9b55c0efe643d8c3a09593f56abf23bcbb26d27b0c6e46a56415d9103ed6b4d8ac7b4182f9f250cafab9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a000082a8648203e800a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f862f860800a83989680940000000000000000000000000000000000001000808026a0e5d462429669f661291a8dc4c49a092cfd4922b6f3f31c9189a2f4adf5ecd730a001494afaf472fbb80bcb107ffeb918a2b9115f454027840615d6d20d63c69ac0c0c0c0", + "rlp": "0xf902c8f9025fa067315ef3267f6f654068ccbd317423b1028fd5305b94a56d1f27e6651e06d678a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa061171b085ffd8d099ca59ba13164e8883d89c89d3298256aa229b03a6e33d246a0ec9d10cff79619f2df45db8c66526ef3fbd32d283fdd2dcc9b55c0efe643d8c3a09593f56abf23bcbb26d27b0c6e46a56415d9103ed6b4d8ac7b4182f9f250cafab9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a000082a8648203e800a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f862f860800a83989680940000000000000000000000000000000000001000808026a0e5d462429669f661291a8dc4c49a092cfd4922b6f3f31c9189a2f4adf5ecd730a001494afaf472fbb80bcb107ffeb918a2b9115f454027840615d6d20d63c69ac0c0c0", "blocknumber": "1" } ], @@ -259,5 +259,5 @@ } } }, - "stdout": "Considering tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]\nBlock 1 (0xfb5d1d0e218fa7873bc188f07f3e0a7c78027ff6e6e199c48ba1facd3c3726fd) Imported\nChain import successful - tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]\n" + "stdout": "Considering tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]\nBlock 1 (0x9ca58820df28ca6d09450fff5fdf93d39976e3aa098c6981ae08f391d44ffb3f) Imported\nChain import successful - tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]\n" } diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-deposit.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-deposit.json index 771dc870e66..f80771a85eb 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-deposit.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-deposit.json @@ -63,8 +63,8 @@ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500", "storage": {} }, - "0x0aae40965e6800cd9b1f4b05ff21581047e3f91e": { - "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500", + "0x0f792be4b0c0cb4dae440ef133e90c0ecd48cccc": { + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", "balance": "0x0", "nonce": "0x1" }, @@ -185,9 +185,9 @@ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe146090573615156028575f545f5260205ff35b366038141561012e5760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061012e57600154600101600155600354806003026004013381556001015f3581556001016020359055600101600355005b6003546002548082038060101160a4575060105b5f5b81811460dd5780604c02838201600302600401805490600101805490600101549160601b83528260140152906034015260010160a6565b910180921460ed579060025560f8565b90505f6002555f6003555b5f548061049d141561010757505f5b60015460028282011161011c5750505f610122565b01600290035b5f555f600155604c025ff35b5f5ffd", "nonce": "0x1" }, - "0x0aae40965e6800cd9b1f4b05ff21581047e3f91e": { + "0x0f792be4b0c0cb4dae440ef133e90c0ecd48cccc": { "balance": "0x0", - "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", "nonce": "0x1", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0xe4fb5d47f70d54b4f36777ea4c882cf767f93d8f8170285d97a1b8275dfe4dbb" @@ -268,7 +268,7 @@ "0x" ], "requestsHash": "0x158ac6beda33cd9341831552555f64c95e074e7024f6c4553c1ed7557077b4c7", - "stateRoot": "0x3aa7839837ee1564276a0a05554e35215353a97c4e255c3aacbcd7c7819daefa", + "stateRoot": "0x6471f6d90b87f759176a0ad62a7096f69d0d24fd873bdb6b6ced57d04a71e274", "txRoot": "0x2b790bf82ef7259a0e4513d1b89a77d81e99672ba68758ef2ba3fde32851d023", "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" } diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal-request.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal-request.json index 615161c88d8..38fd53da0ad 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal-request.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal-request.json @@ -65,10 +65,10 @@ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd", "storage": {} }, - "0x0aae40965e6800cd9b1f4b05ff21581047e3f91e": { + "0x0f792be4b0c0cb4dae440ef133e90c0ecd48cccc": { "nonce": "0x01", "balance": "0x00", - "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", "storage": {} }, "0x000f3df6d732807ef1319fb7b8bb8522d0beac02": { @@ -189,8 +189,8 @@ "balance": "0x0", "nonce": "0x1" }, - "0x0aae40965e6800cd9b1f4b05ff21581047e3f91e":{ - "code":"0x3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500", + "0x0f792be4b0c0cb4dae440ef133e90c0ecd48cccc":{ + "code":"0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", "storage":{ "0x0000000000000000000000000000000000000000000000000000000000000000":"0x10715cfbefdb8a0cb2f7d7ca5ee6d1ea65515ecb41cff0a22d1e11716a9d27fb" }, @@ -219,7 +219,7 @@ "0x00000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000", "0x" ], - "stateRoot": "0x575019750f84d65daf5469b26d05ad8e4335c63011dbca71ca97420cbd80d579", + "stateRoot": "0xc7b49e4aef4229962b94ec0a7c83a6fc0b4015f2573b9a85446ed434c823164e", "txRoot": "0x0d36638e52999b7beafa00eb94f7ca23139774cd14229c011d0edc1fc66125c9", "receiptsRoot": "0x2af83312a6aa55bd8f169e65eec48f92d6d6dc3398bc038d7ccfab5d9aa26b3f", "logsHash": "0xac344ad50aad544ec284bf76ac9b939f93e00f8fe16097a151df14bde2065f83", From 4ae3be55ad4f726b94a6f97c7569b3aa78f6323a Mon Sep 17 00:00:00 2001 From: Matilda-Clerke Date: Thu, 9 Jan 2025 11:06:06 +1100 Subject: [PATCH 4/4] Add GetBodiesFromPeerTask (#8040) * 7311: Add PeerTask system for use in future PRs Signed-off-by: Matilda Clerke * 7311: Clean up some warnings Signed-off-by: Matilda Clerke * 7311: Add feature toggle for enabling use of the peertask system where available Signed-off-by: Matilda Clerke * 7311: Remove log used for testing, apply spotless Signed-off-by: Matilda Clerke * 7311: Add private constructor to PeerTaskFeatureToggle to prevent instantiation Signed-off-by: Matilda Clerke * 7311: Switch to logging a warning instead of throwing an exception when initializing PeerTaskFeatureToggle multiple times Signed-off-by: Matilda Clerke * 7311: Update javadoc to match previous commit Signed-off-by: Matilda Clerke * 7311: spotless Signed-off-by: Matilda Clerke * 7311: Fix broken BesuCommandTest Signed-off-by: Matilda Clerke * 7311: add class Signed-off-by: Matilda Clerke * 7311: Move PeerTaskFeatureToggle to more appropriate location Signed-off-by: Matilda Clerke * 7311: add X prefix to peertask-system-enabled Signed-off-by: Matilda Clerke * 7311: Move --Xpeertask-system-enabled out of BesuCommand and make hidden Signed-off-by: Matilda Clerke * 7311: spotless Signed-off-by: Matilda Clerke * 7311: Add GetReceiptsFromPeerTask Signed-off-by: Matilda Clerke * 7311: Move isPeerTaskSystemEnabled to SynchronizerOptions Signed-off-by: Matilda Clerke * 7311: Fix javadoc issue Signed-off-by: Matilda Clerke * 7311: Fix javadoc issue Signed-off-by: Matilda Clerke * 7311: Move PeerTaskFeatureToggleTestHelper to TestUtil and fix RunnerTest Signed-off-by: Matilda Clerke * 7311: spotless Signed-off-by: Matilda Clerke * 7311: Remove PeerTaskFeatureToggle in favor of including isPeerTaskSystemEnabled in SynchronizerConfiguration Signed-off-by: Matilda Clerke * 7311: Adjust to the removal of PeerTaskFeatureToggle and use SynchronizerConfiguration to get the toggle instead Signed-off-by: Matilda Clerke * 7311: Reduce timeout in PeerTaskRequestSender to 5s Signed-off-by: Matilda Clerke * 7311: Refactor PeerManager to be an interface Signed-off-by: Matilda Clerke * 7311: Fix up compile errors after merge Signed-off-by: Matilda Clerke * 7311: Fix MetricsAcceptanceTest Signed-off-by: Matilda Clerke * 7311: Fix MetricsAcceptanceTest Signed-off-by: Matilda Clerke * 7311: Fix DownloadReceiptsStep when using peer task system Signed-off-by: Matilda Clerke * 7311: Rename PeerManager to PeerSelector Signed-off-by: Matilda Clerke * 7311: Reword PeerSelector javadoc to avoid implementation details Signed-off-by: Matilda Clerke * 7311: Use ConcurrentHashMap in DefaultPeerSelector Signed-off-by: Matilda Clerke * 7311: Reword trace log in DefaultPeerSelector Signed-off-by: Matilda Clerke * 7311: Remove unused imports Signed-off-by: Matilda Clerke * 7311: Use a 1 second delay between retries in PeerTaskExecutor to match old implementation Signed-off-by: Matilda Clerke * 7311: Add testGetPeerButNoPeerMatchesFilter to DefaultPeerSelectorTest Signed-off-by: Matilda Clerke * 7311: Add testGetPeerButNoPeerMatchesFilter to DefaultPeerSelectorTest Signed-off-by: Matilda Clerke * 7311: spotless Signed-off-by: Matilda Clerke * 7311: Fix MetricsAcceptanceTest Signed-off-by: Matilda Clerke * 7311: Fix MetricsAcceptanceTest Signed-off-by: Matilda Clerke * 7311: Modify PeerTaskExecutor metric to include response time from peer Signed-off-by: Matilda Clerke * 7311: Use SubProtocol instead of subprotocol name string in PeerTask Signed-off-by: Matilda Clerke * 7311: rename timing context to ignored to prevent intellij warnings Signed-off-by: Matilda Clerke * 7311: Use constants for number of retries Signed-off-by: Matilda Clerke * 7311: Convert PeerTaskExecutorResult to a record Signed-off-by: Matilda Clerke * 7311: Rename PeerTaskBehavior to PeerTaskRetryBehavior Signed-off-by: Matilda Clerke * 7311: Move peer selection logic to PeerSelector Signed-off-by: Matilda Clerke * 7311: spotless Signed-off-by: Matilda Clerke * 7311: Fix up everything broken after merge Signed-off-by: Matilda Clerke * 7311: Attempt to improve performance of peer task system in pipeline Signed-off-by: Matilda Clerke * 7311: fix compile check Signed-off-by: Matilda Clerke * 7311: Fix broken workflow Signed-off-by: Matilda Clerke * 7311: Reduce logging in JsonRpcExecutor to trace level Signed-off-by: Matilda Clerke * 7311: More changes in DownloadReceiptsStep Signed-off-by: Matilda Clerke * 7311: Rework DownloadReceiptsStep Signed-off-by: Matilda Clerke * 7311: Make changes as discussed in walkthrough meeting Remove DefaultPeerSelector, make EthPeers implement PeerSelector interface, and add PeerTask.getPeerRequirementFilter Signed-off-by: Matilda Clerke * 7311: Update after merge and make discussed changes from walkthrough discussion Signed-off-by: Matilda Clerke * 7311: Change to regular HashMap Signed-off-by: Matilda Clerke * 7311: Remove runtime exception again Signed-off-by: Matilda Clerke * 7311: Rename getPeerTaskBehavior to getPeerTaskRetryBehavior Signed-off-by: Matilda Clerke * 7311: Rename getPeerTaskBehavior to getPeerTaskRetryBehavior Signed-off-by: Matilda Clerke * 7311: Rework PeerTaskExecutor retry system to be 0-based Signed-off-by: Matilda Clerke * 7311: Fix up compile errors after merge Signed-off-by: Matilda Clerke * 7311: Fix broken DownloadReceiptsStepTest test Signed-off-by: Matilda Clerke * 7311: Move GetReceipts to services worker for parallelism Signed-off-by: Matilda Clerke * 7311: Refactor peer task system usage in DownloadReceiptsStep to better match old system Signed-off-by: Matilda Clerke * 7311: Remove unused async methods in PeerTaskExecutor Signed-off-by: Matilda Clerke * 7311: Return Optional in PeerSelector.getPeer and utilise existing peer selection behavior in EthPeers Signed-off-by: Matilda Clerke * 7311: Update after merge Signed-off-by: Matilda Clerke * 7311: Redo getPeer again to include hasAvailableRequestCapacity check Signed-off-by: Matilda Clerke * 7311: Add protocol spec supplier to GetReceiptsFromPeerTask Signed-off-by: Matilda Clerke * 7311: Rework getPeer again to use LEAST_TO_MOST_BUSY comparator Signed-off-by: Matilda Clerke * 7311: Import PeerNotConnected class instead of using fully qualified class name Signed-off-by: Matilda Clerke * 7311: Change to specifying retry counts in PeerTask instead of behavior enums Signed-off-by: Matilda Clerke * 7311: clean up after merge Signed-off-by: Matilda Clerke * 7311: clean up after merge Signed-off-by: Matilda Clerke * 7311: Fix up javadoc Signed-off-by: Matilda Clerke * 7311: Add additional metrics to PeerTaskExecutor Signed-off-by: Matilda Clerke * 7311: Add Predicate to PeerTask to check for partial success Signed-off-by: Matilda Clerke * 7311: Fix incorrect name on isPartialSuccessTest Signed-off-by: Matilda Clerke * 7311: Implement isPartialSuccess and add unit tests Signed-off-by: Matilda Clerke * 7311: Add partialSuccessCounter and inflightRequestGauge in PeerTaskExecutor Signed-off-by: Matilda Clerke * 7311: Also filter by whether a peer is fully validated Signed-off-by: Matilda Clerke * 7311: Remove unneeded throws in RunnerTest Signed-off-by: Matilda Clerke * 7311: Fix up inflight requests gauge in PeerTaskExecutor Signed-off-by: Matilda Clerke * 7311: Update plugin api hash Signed-off-by: Matilda Clerke * 7311: Update plugin api hash Signed-off-by: Matilda Clerke * 7311: Add javadoc to LabelledGauge.isLabelsObserved Signed-off-by: Matilda Clerke * 7311: Update plugin-api hash Signed-off-by: Matilda Clerke * 7311: Update changelog Signed-off-by: Matilda Clerke * 7311: Handle headers with no receipts as a special case in DownloadReceiptsStep Signed-off-by: Matilda Clerke * 7311: Complete merge Signed-off-by: Matilda Clerke * 7311: Use taskName instead of className for labelNames Signed-off-by: Matilda Clerke * 7311: Use snake_case for metric names Signed-off-by: Matilda Clerke * 7311: Use _total metric name suffix Signed-off-by: Matilda Clerke * 7311: rework partial success handling Signed-off-by: Matilda Clerke * 7311: Update GetReceiptsFromPeerTask with partialSuccess changes Signed-off-by: Matilda Clerke * 7311: Add default implementation to LabelledGauge.isLabelsObserved Signed-off-by: Matilda Clerke * 7311: Fix broken unit test Signed-off-by: Matilda Clerke * 7311: Rename parseResponse to processResponse Signed-off-by: Matilda Clerke * add possibility to use the new peer task system when downloading the bodies Signed-off-by: stefan.pingel@consensys.net * fix loop Signed-off-by: stefan.pingel@consensys.net * 7311: Wrap peer task system usage in ethScheduler call to match other usages Signed-off-by: Matilda Clerke * small fixes Signed-off-by: stefan.pingel@consensys.net * update API change Signed-off-by: stefan.pingel@consensys.net * spotless Signed-off-by: stefan.pingel@consensys.net * 7311: apply spotless Signed-off-by: Matilda Clerke * 7311: Move check for empty trie hash into GetReceiptsFromPeerTask and update unit test to test for this functionality Signed-off-by: Matilda Clerke * 7311: spotless Signed-off-by: Matilda Clerke * 7311: Fix compile issue after merge Signed-off-by: Matilda Clerke * 7311: Remove BodyValidator and update code and test to match Signed-off-by: Matilda Clerke * 7311: spotless Signed-off-by: Matilda Clerke * 7311: Fix up pre-fill and add test to test failure scenario Signed-off-by: Matilda Clerke * 7311: Use ProtocolSchedule.anyMatch to find if any ProtocolSpecs are PoS, remove new usages of currentProtocolSpecSupplier Signed-off-by: Matilda Clerke * 7311: Only attempt to remove headers on successful requests Signed-off-by: Matilda Clerke * 7311: Fix broken stuff after merge Signed-off-by: Matilda Clerke * spotless Signed-off-by: stefan.pingel@consensys.net * Fix up compile errors after merge Signed-off-by: Matilda Clerke * Add PeerTaskExecutor usage for GetBodies in DownloadHeaderSequenceTask Signed-off-by: Matilda Clerke * Add PeerTaskExecutor usage for GetBodies in ForwardSyncStep and apply spotless Signed-off-by: Matilda Clerke * Allow custom retries against other peers in GetBodiesFromPeerTask Signed-off-by: Matilda Clerke * Fix infinite loop in CheckPointSyncChainDownloaderTest Signed-off-by: Matilda Clerke * spotless Signed-off-by: Matilda Clerke * Update CompleteBlocksWithPeerTask.getBlocks to retrieveBlocksFromPeers and add javadoc Signed-off-by: Matilda Clerke * Add javadoc to GetBodiesFromPeerTask Signed-off-by: Matilda Clerke * 7582: Simplify withdrawals validation Signed-off-by: Matilda Clerke --------- Signed-off-by: Matilda Clerke Signed-off-by: stefan.pingel@consensys.net Co-authored-by: Sally MacFarlane Co-authored-by: stefan.pingel@consensys.net --- .../peertask/task/GetBodiesFromPeerTask.java | 163 +++++++++++ .../eth/sync/DefaultSynchronizer.java | 1 + .../ethereum/eth/sync/DownloadBodiesStep.java | 24 +- .../sync/backwardsync/ForwardSyncStep.java | 65 +++-- .../FastSyncDownloadPipelineFactory.java | 2 +- .../fullsync/FullSyncChainDownloader.java | 4 +- .../FullSyncDownloadPipelineFactory.java | 5 +- .../eth/sync/fullsync/FullSyncDownloader.java | 5 +- .../tasks/CompleteBlocksWithPeerTask.java | 135 ++++++++++ .../tasks/DownloadHeaderSequenceTask.java | 60 +++-- .../task/GetBodiesFromPeerTaskTest.java | 189 +++++++++++++ .../backwardsync/ForwardSyncStepTest.java | 59 +++- .../CheckPointSyncChainDownloaderTest.java | 18 ++ .../FullSyncChainDownloaderForkTest.java | 5 +- .../fullsync/FullSyncChainDownloaderTest.java | 5 +- ...DownloaderTotalTerminalDifficultyTest.java | 5 +- .../sync/fullsync/FullSyncDownloaderTest.java | 1 + .../tasks/CompleteBlocksWithPeerTaskTest.java | 253 ++++++++++++++++++ .../tasks/DownloadHeaderSequenceTaskTest.java | 22 ++ 19 files changed, 970 insertions(+), 51 deletions(-) create mode 100644 ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetBodiesFromPeerTask.java create mode 100644 ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksWithPeerTask.java create mode 100644 ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetBodiesFromPeerTaskTest.java create mode 100644 ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksWithPeerTaskTest.java diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetBodiesFromPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetBodiesFromPeerTask.java new file mode 100644 index 00000000000..a59183b14ac --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetBodiesFromPeerTask.java @@ -0,0 +1,163 @@ +/* + * 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.eth.manager.peertask.task; + +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.eth.EthProtocol; +import org.hyperledger.besu.ethereum.eth.manager.EthPeer; +import org.hyperledger.besu.ethereum.eth.manager.peertask.InvalidPeerTaskResponseException; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTask; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskValidationResponse; +import org.hyperledger.besu.ethereum.eth.messages.BlockBodiesMessage; +import org.hyperledger.besu.ethereum.eth.messages.GetBlockBodiesMessage; +import org.hyperledger.besu.ethereum.mainnet.BodyValidation; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.SubProtocol; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implements PeerTask for getting block bodies from peers, and matches headers to bodies to supply + * full blocks + */ +public class GetBodiesFromPeerTask implements PeerTask> { + + private static final Logger LOG = LoggerFactory.getLogger(GetBodiesFromPeerTask.class); + + private static final int DEFAULT_RETRIES_AGAINST_OTHER_PEERS = 5; + + private final List blockHeaders; + private final ProtocolSchedule protocolSchedule; + private final int allowedRetriesAgainstOtherPeers; + + private final long requiredBlockchainHeight; + private final List blocks = new ArrayList<>(); + private final boolean isPoS; + + public GetBodiesFromPeerTask( + final List blockHeaders, final ProtocolSchedule protocolSchedule) { + this(blockHeaders, protocolSchedule, DEFAULT_RETRIES_AGAINST_OTHER_PEERS); + } + + public GetBodiesFromPeerTask( + final List blockHeaders, + final ProtocolSchedule protocolSchedule, + final int allowedRetriesAgainstOtherPeers) { + if (blockHeaders == null || blockHeaders.isEmpty()) { + throw new IllegalArgumentException("Block headers must not be empty"); + } + + this.blockHeaders = blockHeaders; + this.protocolSchedule = protocolSchedule; + this.allowedRetriesAgainstOtherPeers = allowedRetriesAgainstOtherPeers; + + this.requiredBlockchainHeight = + blockHeaders.stream() + .mapToLong(BlockHeader::getNumber) + .max() + .orElse(BlockHeader.GENESIS_BLOCK_NUMBER); + this.isPoS = protocolSchedule.getByBlockHeader(blockHeaders.getLast()).isPoS(); + } + + @Override + public SubProtocol getSubProtocol() { + return EthProtocol.get(); + } + + @Override + public MessageData getRequestMessage() { + return GetBlockBodiesMessage.create( + blockHeaders.stream().map(BlockHeader::getBlockHash).toList()); + } + + @Override + public List processResponse(final MessageData messageData) + throws InvalidPeerTaskResponseException { + // Blocks returned by this method are in the same order as the headers, but might not be + // complete + if (messageData == null) { + throw new InvalidPeerTaskResponseException(); + } + final BlockBodiesMessage blocksMessage = BlockBodiesMessage.readFrom(messageData); + final List blockBodies = blocksMessage.bodies(protocolSchedule); + if (blockBodies.isEmpty() || blockBodies.size() > blockHeaders.size()) { + throw new InvalidPeerTaskResponseException(); + } + + for (int i = 0; i < blockBodies.size(); i++) { + final BlockBody blockBody = blockBodies.get(i); + final BlockHeader blockHeader = blockHeaders.get(i); + if (!blockBodyMatchesBlockHeader(blockBody, blockHeader)) { + LOG.atDebug().setMessage("Received block body does not match block header").log(); + throw new InvalidPeerTaskResponseException(); + } + + blocks.add(new Block(blockHeader, blockBody)); + } + return blocks; + } + + @Override + public int getRetriesWithOtherPeer() { + return allowedRetriesAgainstOtherPeers; + } + + private boolean blockBodyMatchesBlockHeader( + final BlockBody blockBody, final BlockHeader blockHeader) { + // this method validates that the block body matches the block header by calculating the roots + // of the block body and comparing them to the roots in the block header + if (!BodyValidation.transactionsRoot(blockBody.getTransactions()) + .equals(blockHeader.getTransactionsRoot())) { + return false; + } + if (!BodyValidation.ommersHash(blockBody.getOmmers()).equals(blockHeader.getOmmersHash())) { + return false; + } + if (!blockBody + .getWithdrawals() + .map(BodyValidation::withdrawalsRoot) + .equals(blockHeader.getWithdrawalsRoot())) { + return false; + } + + return true; + } + + @Override + public Predicate getPeerRequirementFilter() { + return (ethPeer) -> + isPoS || ethPeer.chainState().getEstimatedHeight() >= requiredBlockchainHeight; + } + + @Override + public PeerTaskValidationResponse validateResult(final List result) { + if (result.isEmpty()) { + return PeerTaskValidationResponse.NO_RESULTS_RETURNED; + } + return PeerTaskValidationResponse.RESULTS_VALID_AND_GOOD; + } + + public List getBlockHeaders() { + return blockHeaders; + } +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java index 43dfa275eba..c872f195103 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java @@ -137,6 +137,7 @@ public DefaultSynchronizer( syncState, metricsSystem, terminationCondition, + peerTaskExecutor, syncDurationMetrics)); if (SyncMode.FAST.equals(syncConfig.getSyncMode())) { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DownloadBodiesStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DownloadBodiesStep.java index 26fc7b544ce..d65d8e82407 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DownloadBodiesStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DownloadBodiesStep.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.sync.tasks.CompleteBlocksTask; +import org.hyperledger.besu.ethereum.eth.sync.tasks.CompleteBlocksWithPeerTask; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.plugin.services.MetricsSystem; @@ -31,19 +32,38 @@ public class DownloadBodiesStep private final ProtocolSchedule protocolSchedule; private final EthContext ethContext; private final MetricsSystem metricsSystem; + private final SynchronizerConfiguration synchronizerConfiguration; public DownloadBodiesStep( final ProtocolSchedule protocolSchedule, final EthContext ethContext, + final SynchronizerConfiguration synchronizerConfiguration, final MetricsSystem metricsSystem) { this.protocolSchedule = protocolSchedule; this.ethContext = ethContext; + this.synchronizerConfiguration = synchronizerConfiguration; this.metricsSystem = metricsSystem; } @Override public CompletableFuture> apply(final List blockHeaders) { - return CompleteBlocksTask.forHeaders(protocolSchedule, ethContext, blockHeaders, metricsSystem) - .run(); + if (synchronizerConfiguration.isPeerTaskSystemEnabled()) { + return ethContext + .getScheduler() + .scheduleServiceTask(() -> getBodiesWithPeerTaskSystem(blockHeaders)); + } else { + return CompleteBlocksTask.forHeaders( + protocolSchedule, ethContext, blockHeaders, metricsSystem) + .run(); + } + } + + private CompletableFuture> getBodiesWithPeerTaskSystem( + final List headers) { + + final CompleteBlocksWithPeerTask completeBlocksWithPeerTask = + new CompleteBlocksWithPeerTask(protocolSchedule, headers, ethContext.getPeerTaskExecutor()); + final List blocks = completeBlocksWithPeerTask.retrieveBlocksFromPeers(); + return CompletableFuture.completedFuture(blocks); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStep.java index c1ce88398e4..0f968e90839 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStep.java @@ -16,6 +16,9 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult; +import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetBodiesFromPeerTask; import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask; import org.hyperledger.besu.ethereum.eth.manager.task.RetryingGetBlocksFromPeersTask; @@ -53,9 +56,9 @@ public CompletableFuture possibleRequestBodies(final List blo LOG.atDebug() .setMessage("Requesting {} blocks {}->{} ({})") .addArgument(blockHeaders::size) - .addArgument(() -> blockHeaders.get(0).getNumber()) - .addArgument(() -> blockHeaders.get(blockHeaders.size() - 1).getNumber()) - .addArgument(() -> blockHeaders.get(0).getHash().toHexString()) + .addArgument(() -> blockHeaders.getFirst().getNumber()) + .addArgument(() -> blockHeaders.getLast().getNumber()) + .addArgument(() -> blockHeaders.getFirst().getHash().toHexString()) .log(); return requestBodies(blockHeaders) .thenApply(this::saveBlocks) @@ -76,23 +79,47 @@ public CompletableFuture possibleRequestBodies(final List blo @VisibleForTesting protected CompletableFuture> requestBodies(final List blockHeaders) { - final RetryingGetBlocksFromPeersTask getBodiesFromPeerTask = - RetryingGetBlocksFromPeersTask.forHeaders( - context.getProtocolSchedule(), - context.getEthContext(), - context.getMetricsSystem(), - context.getEthContext().getEthPeers().peerCount(), - blockHeaders); + CompletableFuture> blocksFuture; + if (context.getSynchronizerConfiguration().isPeerTaskSystemEnabled()) { + blocksFuture = + context + .getEthContext() + .getScheduler() + .scheduleServiceTask( + () -> { + GetBodiesFromPeerTask task = + new GetBodiesFromPeerTask( + blockHeaders, + context.getProtocolSchedule(), + context.getEthContext().getEthPeers().peerCount()); + PeerTaskExecutorResult> taskResult = + context.getEthContext().getPeerTaskExecutor().execute(task); + if (taskResult.responseCode() == PeerTaskExecutorResponseCode.SUCCESS + && taskResult.result().isPresent()) { + return CompletableFuture.completedFuture(taskResult.result().get()); + } else { + return CompletableFuture.failedFuture( + new RuntimeException(taskResult.responseCode().toString())); + } + }); + } else { + final RetryingGetBlocksFromPeersTask getBodiesFromPeerTask = + RetryingGetBlocksFromPeersTask.forHeaders( + context.getProtocolSchedule(), + context.getEthContext(), + context.getMetricsSystem(), + context.getEthContext().getEthPeers().peerCount(), + blockHeaders); - final CompletableFuture>> run = - getBodiesFromPeerTask.run(); - return run.thenApply(AbstractPeerTask.PeerTaskResult::getResult) - .thenApply( - blocks -> { - LOG.debug("Got {} blocks from peers", blocks.size()); - blocks.sort(Comparator.comparing(block -> block.getHeader().getNumber())); - return blocks; - }); + blocksFuture = + getBodiesFromPeerTask.run().thenApply(AbstractPeerTask.PeerTaskResult::getResult); + } + return blocksFuture.thenApply( + blocks -> { + LOG.debug("Got {} blocks from peers", blocks.size()); + blocks.sort(Comparator.comparing(block -> block.getHeader().getNumber())); + return blocks; + }); } @VisibleForTesting 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 707fc6aa13f..8eebd2ea42d 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 @@ -140,7 +140,7 @@ public Pipeline createDownloadPipelineForSyncTarget(final SyncT final RangeHeadersValidationStep validateHeadersJoinUpStep = new RangeHeadersValidationStep(protocolSchedule, protocolContext, detachedValidationPolicy); final DownloadBodiesStep downloadBodiesStep = - new DownloadBodiesStep(protocolSchedule, ethContext, metricsSystem); + new DownloadBodiesStep(protocolSchedule, ethContext, syncConfig, metricsSystem); final DownloadReceiptsStep downloadReceiptsStep = new DownloadReceiptsStep(protocolSchedule, ethContext, syncConfig, metricsSystem); final ImportBlocksStep importBlockStep = diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloader.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloader.java index 3a0f6edb086..5be4942603f 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloader.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloader.java @@ -16,6 +16,7 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.PipelineChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; @@ -35,7 +36,8 @@ public static ChainDownloader create( final SyncState syncState, final MetricsSystem metricsSystem, final SyncTerminationCondition terminationCondition, - final SyncDurationMetrics syncDurationMetrics) { + final SyncDurationMetrics syncDurationMetrics, + final PeerTaskExecutor peerTaskExecutor) { final FullSyncTargetManager syncTargetManager = new FullSyncTargetManager( diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloadPipelineFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloadPipelineFactory.java index 570ef303779..109dd42b1a3 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloadPipelineFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloadPipelineFactory.java @@ -67,7 +67,8 @@ public FullSyncDownloadPipelineFactory( this.ethContext = ethContext; this.metricsSystem = metricsSystem; this.fullSyncTerminationCondition = syncTerminationCondition; - betterSyncTargetEvaluator = new BetterSyncTargetEvaluator(syncConfig, ethContext.getEthPeers()); + this.betterSyncTargetEvaluator = + new BetterSyncTargetEvaluator(syncConfig, ethContext.getEthPeers()); } @Override @@ -105,7 +106,7 @@ public Pipeline createDownloadPipelineForSyncTarget(final SyncTarget target) final RangeHeadersValidationStep validateHeadersJoinUpStep = new RangeHeadersValidationStep(protocolSchedule, protocolContext, detachedValidationPolicy); final DownloadBodiesStep downloadBodiesStep = - new DownloadBodiesStep(protocolSchedule, ethContext, metricsSystem); + new DownloadBodiesStep(protocolSchedule, ethContext, syncConfig, metricsSystem); final ExtractTxSignaturesStep extractTxSignaturesStep = new ExtractTxSignaturesStep(); final FullImportBlockStep importBlockStep = new FullImportBlockStep( diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloader.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloader.java index 8f1aca792c3..97bf38c95ec 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloader.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloader.java @@ -16,6 +16,7 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.TrailingPeerRequirements; @@ -45,6 +46,7 @@ public FullSyncDownloader( final SyncState syncState, final MetricsSystem metricsSystem, final SyncTerminationCondition terminationCondition, + final PeerTaskExecutor peerTaskExecutor, final SyncDurationMetrics syncDurationMetrics) { this.syncConfig = syncConfig; this.protocolContext = protocolContext; @@ -59,7 +61,8 @@ public FullSyncDownloader( syncState, metricsSystem, terminationCondition, - syncDurationMetrics); + syncDurationMetrics, + peerTaskExecutor); } public CompletableFuture start() { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksWithPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksWithPeerTask.java new file mode 100644 index 00000000000..70e17ca1fc2 --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksWithPeerTask.java @@ -0,0 +1,135 @@ +/* + * 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.eth.sync.tasks; + +import static com.google.common.base.Preconditions.checkArgument; + +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult; +import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetBodiesFromPeerTask; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Given a set of headers, "completes" them by repeatedly requesting additional data (bodies) needed + * to create the blocks that correspond to the supplied headers. + */ +public class CompleteBlocksWithPeerTask { + private static final Logger LOG = LoggerFactory.getLogger(CompleteBlocksWithPeerTask.class); + + private final ProtocolSchedule protocolSchedule; + private final List headersToGet = new ArrayList<>(); + private final PeerTaskExecutor peerTaskExecutor; + + private final Block[] result; + private final int resultSize; + private int nextIndex = 0; + private int remainingBlocks; + + public CompleteBlocksWithPeerTask( + final ProtocolSchedule protocolSchedule, + final List headers, + final PeerTaskExecutor peerTaskExecutor) { + checkArgument(!headers.isEmpty(), "Must supply a non-empty headers list"); + this.protocolSchedule = protocolSchedule; + this.peerTaskExecutor = peerTaskExecutor; + + resultSize = headers.size(); + result = new Block[resultSize]; + remainingBlocks = resultSize; + + for (int i = 0; i < resultSize; i++) { + final BlockHeader header = headers.get(i); + if (BlockHeader.hasEmptyBlock(header)) { + final Block emptyBlock = + new Block(header, createEmptyBodyBasedOnProtocolSchedule(protocolSchedule, header)); + result[i] = emptyBlock; + remainingBlocks--; + } else { + headersToGet.add(header); + } + } + this.nextIndex = findNextIndex(0); + } + + private BlockBody createEmptyBodyBasedOnProtocolSchedule( + final ProtocolSchedule protocolSchedule, final BlockHeader header) { + return new BlockBody( + Collections.emptyList(), + Collections.emptyList(), + isWithdrawalsEnabled(protocolSchedule, header) + ? Optional.of(Collections.emptyList()) + : Optional.empty()); + } + + private boolean isWithdrawalsEnabled( + final ProtocolSchedule protocolSchedule, final BlockHeader header) { + return protocolSchedule.getByBlockHeader(header).getWithdrawalsProcessor().isPresent(); + } + + /** + * Retrieves all remaining blocks from connected peers. Subsequent calls will have no affect. + * + * @return A List of all blocks for the headers supplied when constructing this + * CompleteBlocksWithPeerTask + */ + public List retrieveBlocksFromPeers() { + while (remainingBlocks > 0) { + LOG.atDebug() + .setMessage("Requesting {} bodies from peer") + .addArgument(headersToGet.size()) + .log(); + final GetBodiesFromPeerTask task = new GetBodiesFromPeerTask(headersToGet, protocolSchedule); + final PeerTaskExecutorResult> executionResult = peerTaskExecutor.execute(task); + if (executionResult.responseCode() == PeerTaskExecutorResponseCode.SUCCESS + && executionResult.result().isPresent()) { + final List blockList = executionResult.result().get(); + LOG.atDebug() + .setMessage("Received {} bodies out of {} from peer") + .addArgument(blockList.size()) + .addArgument(headersToGet.size()) + .log(); + blockList.forEach( + block -> { + remainingBlocks--; + result[nextIndex] = block; + headersToGet.removeFirst(); + nextIndex = findNextIndex(nextIndex + 1); + }); + } + } + return List.of(result); + } + + private int findNextIndex(final int startIndex) { + for (int i = startIndex; i < resultSize; i++) { + if (result[i] == null) { + return i; + } + } + return -1; // This only happens when we have finished processing all headers + } +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java index 5eee6495ebd..9a8529c033c 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java @@ -27,11 +27,11 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeer; import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode; import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult; +import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetBodiesFromPeerTask; import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetHeadersFromPeerTask; import org.hyperledger.besu.ethereum.eth.manager.task.AbstractGetHeadersFromPeerTask; import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask.PeerTaskResult; import org.hyperledger.besu.ethereum.eth.manager.task.AbstractRetryingPeerTask; -import org.hyperledger.besu.ethereum.eth.manager.task.GetBodiesFromPeerTask; import org.hyperledger.besu.ethereum.eth.manager.task.GetHeadersFromPeerByHashTask; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.ValidationPolicy; @@ -323,26 +323,44 @@ private CompletableFuture markBadBlock(final BlockHeader badHeader, final Eth // even though the header is known bad we are downloading the block body for the debug_badBlocks // RPC final BadBlockManager badBlockManager = protocolContext.getBadBlockManager(); - return GetBodiesFromPeerTask.forHeaders( - protocolSchedule, ethContext, List.of(badHeader), metricsSystem) - .assignPeer(badPeer) - .run() - .whenComplete( - (blockPeerTaskResult, error) -> { - final HeaderValidationMode validationMode = - validationPolicy.getValidationModeForNextBlock(); - final String description = - String.format("Failed header validation (%s)", validationMode); - final BadBlockCause cause = BadBlockCause.fromValidationFailure(description); - if (blockPeerTaskResult != null) { - final Optional block = blockPeerTaskResult.getResult().stream().findFirst(); - block.ifPresentOrElse( - (b) -> badBlockManager.addBadBlock(b, cause), - () -> badBlockManager.addBadHeader(badHeader, cause)); - } else { - badBlockManager.addBadHeader(badHeader, cause); - } - }); + CompletableFuture blockFuture; + if (synchronizerConfiguration.isPeerTaskSystemEnabled()) { + blockFuture = + ethContext + .getScheduler() + .scheduleServiceTask( + () -> { + GetBodiesFromPeerTask task = + new GetBodiesFromPeerTask(List.of(badHeader), protocolSchedule); + PeerTaskExecutorResult> taskResult = + ethContext.getPeerTaskExecutor().executeAgainstPeer(task, badPeer); + if (taskResult.responseCode() == PeerTaskExecutorResponseCode.SUCCESS) { + return CompletableFuture.completedFuture( + taskResult.result().map(List::getFirst).orElse(null)); + } else { + return CompletableFuture.failedFuture(new RuntimeException()); + } + }); + } else { + blockFuture = + org.hyperledger.besu.ethereum.eth.manager.task.GetBodiesFromPeerTask.forHeaders( + protocolSchedule, ethContext, List.of(badHeader), metricsSystem) + .assignPeer(badPeer) + .run() + .thenApply((blockPeerTaskResult) -> blockPeerTaskResult.getResult().getFirst()); + } + return blockFuture.whenComplete( + (blockResult, error) -> { + final HeaderValidationMode validationMode = + validationPolicy.getValidationModeForNextBlock(); + final String description = String.format("Failed header validation (%s)", validationMode); + final BadBlockCause cause = BadBlockCause.fromValidationFailure(description); + if (blockResult != null) { + badBlockManager.addBadBlock(blockResult, cause); + } else { + badBlockManager.addBadHeader(badHeader, cause); + } + }); } private boolean checkHeaderInRange(final BlockHeader header) { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetBodiesFromPeerTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetBodiesFromPeerTaskTest.java new file mode 100644 index 00000000000..288ddd4ce5a --- /dev/null +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetBodiesFromPeerTaskTest.java @@ -0,0 +1,189 @@ +/* + * 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.eth.manager.peertask.task; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; +import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; +import org.hyperledger.besu.ethereum.eth.EthProtocol; +import org.hyperledger.besu.ethereum.eth.manager.ChainState; +import org.hyperledger.besu.ethereum.eth.manager.EthPeer; +import org.hyperledger.besu.ethereum.eth.manager.peertask.InvalidPeerTaskResponseException; +import org.hyperledger.besu.ethereum.eth.messages.BlockBodiesMessage; +import org.hyperledger.besu.ethereum.eth.messages.EthPV62; +import org.hyperledger.besu.ethereum.eth.messages.GetBlockBodiesMessage; +import org.hyperledger.besu.ethereum.mainnet.BodyValidation; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; +import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.apache.commons.lang3.StringUtils; +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class GetBodiesFromPeerTaskTest { + + private static final String FRONTIER_TX_RLP = + "0xf901fc8032830138808080b901ae60056013565b6101918061001d6000396000f35b3360008190555056006001600060e060020a6000350480630a874df61461003a57806341c0e1b514610058578063a02b161e14610066578063dbbdf0831461007757005b610045600435610149565b80600160a060020a031660005260206000f35b610060610161565b60006000f35b6100716004356100d4565b60006000f35b61008560043560243561008b565b60006000f35b600054600160a060020a031632600160a060020a031614156100ac576100b1565b6100d0565b8060018360005260205260406000208190555081600060005260206000a15b5050565b600054600160a060020a031633600160a060020a031614158015610118575033600160a060020a0316600182600052602052604060002054600160a060020a031614155b61012157610126565b610146565b600060018260005260205260406000208190555080600060005260206000a15b50565b60006001826000526020526040600020549050919050565b600054600160a060020a031633600160a060020a0316146101815761018f565b600054600160a060020a0316ff5b561ca0c5689ed1ad124753d54576dfb4b571465a41900a1dff4058d8adf16f752013d0a01221cbd70ec28c94a3b55ec771bcbc70778d6ee0b51ca7ea9514594c861b1884"; + + private static final Transaction TX = + TransactionDecoder.decodeRLP( + new BytesValueRLPInput(Bytes.fromHexString(FRONTIER_TX_RLP), false), + EncodingContext.BLOCK_BODY); + public static final List TRANSACTION_LIST = List.of(TX); + public static final BlockBody BLOCK_BODY = + new BlockBody(TRANSACTION_LIST, Collections.emptyList(), Optional.empty()); + private static ProtocolSchedule protocolSchedule; + + @BeforeAll + public static void setup() { + protocolSchedule = mock(ProtocolSchedule.class); + final ProtocolSpec protocolSpec = mock(ProtocolSpec.class); + when(protocolSpec.isPoS()).thenReturn(true); + when(protocolSchedule.getByBlockHeader(Mockito.any())).thenReturn(protocolSpec); + } + + @Test + public void testGetSubProtocol() { + + GetBodiesFromPeerTask task = + new GetBodiesFromPeerTask(List.of(mockBlockHeader(0)), protocolSchedule); + Assertions.assertEquals(EthProtocol.get(), task.getSubProtocol()); + } + + @Test + public void testGetRequestMessage() { + GetBodiesFromPeerTask task = + new GetBodiesFromPeerTask( + List.of(mockBlockHeader(1), mockBlockHeader(2), mockBlockHeader(3)), protocolSchedule); + + MessageData messageData = task.getRequestMessage(); + GetBlockBodiesMessage getBlockBodiesMessage = GetBlockBodiesMessage.readFrom(messageData); + + Assertions.assertEquals(EthPV62.GET_BLOCK_BODIES, getBlockBodiesMessage.getCode()); + Iterable hashesInMessage = getBlockBodiesMessage.hashes(); + List expectedHashes = + List.of( + Hash.fromHexString(StringUtils.repeat("00", 31) + "11"), + Hash.fromHexString(StringUtils.repeat("00", 31) + "21"), + Hash.fromHexString(StringUtils.repeat("00", 31) + "31")); + List actualHashes = new ArrayList<>(); + hashesInMessage.forEach(actualHashes::add); + + Assertions.assertEquals(3, actualHashes.size()); + Assertions.assertEquals( + expectedHashes.stream().sorted().toList(), actualHashes.stream().sorted().toList()); + } + + @Test + public void testParseResponseWithNullResponseMessage() { + Assertions.assertThrows( + IllegalArgumentException.class, + () -> new GetBodiesFromPeerTask(Collections.emptyList(), protocolSchedule)); + } + + @Test + public void testParseResponseForInvalidResponse() { + GetBodiesFromPeerTask task = + new GetBodiesFromPeerTask(List.of(mockBlockHeader(1)), protocolSchedule); + // body does not match header + BlockBodiesMessage bodiesMessage = BlockBodiesMessage.create(List.of(BLOCK_BODY)); + + Assertions.assertThrows( + InvalidPeerTaskResponseException.class, () -> task.processResponse(bodiesMessage)); + } + + @Test + public void testParseResponse() throws InvalidPeerTaskResponseException { + final BlockHeader nonEmptyBlockHeaderMock = + getNonEmptyBlockHeaderMock(BodyValidation.transactionsRoot(TRANSACTION_LIST).toString()); + + GetBodiesFromPeerTask task = + new GetBodiesFromPeerTask(List.of(nonEmptyBlockHeaderMock), protocolSchedule); + + final BlockBodiesMessage blockBodiesMessage = BlockBodiesMessage.create(List.of(BLOCK_BODY)); + + List result = task.processResponse(blockBodiesMessage); + + assertThat(result.size()).isEqualTo(1); + assertThat(result.getFirst().getBody().getTransactions()).isEqualTo(TRANSACTION_LIST); + } + + @Test + public void testGetPeerRequirementFilter() { + BlockHeader blockHeader1 = mockBlockHeader(1); + BlockHeader blockHeader2 = mockBlockHeader(2); + BlockHeader blockHeader3 = mockBlockHeader(3); + + GetBodiesFromPeerTask task = + new GetBodiesFromPeerTask( + List.of(blockHeader1, blockHeader2, blockHeader3), protocolSchedule); + + EthPeer successfulCandidate = mockPeer(5); + + Assertions.assertTrue(task.getPeerRequirementFilter().test(successfulCandidate)); + } + + private BlockHeader mockBlockHeader(final long blockNumber) { + BlockHeader blockHeader = Mockito.mock(BlockHeader.class); + Mockito.when(blockHeader.getNumber()).thenReturn(blockNumber); + // second to last hex digit indicates the blockNumber, last hex digit indicates the usage of the + // hash + Mockito.when(blockHeader.getHash()) + .thenReturn(Hash.fromHexString(StringUtils.repeat("00", 31) + blockNumber + "1")); + Mockito.when(blockHeader.getBlockHash()) + .thenReturn(Hash.fromHexString(StringUtils.repeat("00", 31) + blockNumber + "1")); + Mockito.when(blockHeader.getReceiptsRoot()) + .thenReturn(Hash.fromHexString(StringUtils.repeat("00", 31) + blockNumber + "2")); + + return blockHeader; + } + + private static BlockHeader getNonEmptyBlockHeaderMock(final String transactionsRootHexString) { + final BlockHeader blockHeader = mock(BlockHeader.class); + when(blockHeader.getTransactionsRoot()) + .thenReturn(Hash.fromHexStringLenient(transactionsRootHexString)); + when(blockHeader.getOmmersHash()).thenReturn(Hash.EMPTY_LIST_HASH); + when(blockHeader.getWithdrawalsRoot()).thenReturn(Optional.empty()); + return blockHeader; + } + + private EthPeer mockPeer(final long chainHeight) { + EthPeer ethPeer = Mockito.mock(EthPeer.class); + ChainState chainState = Mockito.mock(ChainState.class); + + Mockito.when(ethPeer.chainState()).thenReturn(chainState); + Mockito.when(chainState.getEstimatedHeight()).thenReturn(chainHeight); + + return ethPeer; + } +} diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java index 7104ae31730..86e1aaa687c 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java @@ -35,6 +35,11 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestBuilder; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult; +import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetBodiesFromPeerTask; +import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; @@ -47,6 +52,7 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import javax.annotation.Nonnull; import org.assertj.core.api.Assertions; @@ -70,6 +76,9 @@ public class ForwardSyncStepTest { @Mock(answer = Answers.RETURNS_DEEP_STUBS) private BackwardSyncContext context; + @Mock private SynchronizerConfiguration syncConfig; + @Mock private PeerTaskExecutor peerTaskExecutor; + private MutableBlockchain remoteBlockchain; private RespondingEthPeer peer; @@ -128,7 +137,12 @@ public void setup() { when(context.getProtocolContext().getBlockchain()).thenReturn(localBlockchain); when(context.getProtocolSchedule()).thenReturn(protocolSchedule); when(context.getBatchSize()).thenReturn(2); - EthProtocolManager ethProtocolManager = EthProtocolManagerTestBuilder.builder().build(); + when(context.getSynchronizerConfiguration()).thenReturn(syncConfig); + EthProtocolManager ethProtocolManager = + EthProtocolManagerTestBuilder.builder() + .setSynchronizerConfiguration(syncConfig) + .setPeerTaskExecutor(peerTaskExecutor) + .build(); peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager); EthContext ethContext = ethProtocolManager.ethContext(); @@ -147,10 +161,28 @@ public void setup() { ForestReferenceTestWorldState.create(Collections.emptyMap()), blockDataGenerator.receipts(block)))); }); + + when(peerTaskExecutor.execute(any(GetBodiesFromPeerTask.class))) + .thenAnswer( + (invocationOnMock) -> { + GetBodiesFromPeerTask task = + invocationOnMock.getArgument(0, GetBodiesFromPeerTask.class); + List blocks = + task.getBlockHeaders().stream() + .map( + (bh) -> + new Block(bh, remoteBlockchain.getBlockBody(bh.getBlockHash()).get())) + .collect(Collectors.toList()); + return new PeerTaskExecutorResult>( + Optional.of(blocks), + PeerTaskExecutorResponseCode.SUCCESS, + Optional.of(peer.getEthPeer())); + }); } @Test public void shouldExecuteForwardSyncWhenPossible() throws Exception { + when(syncConfig.isPeerTaskSystemEnabled()).thenReturn(false); final BackwardChain backwardChain = createBackwardChain(LOCAL_HEIGHT, LOCAL_HEIGHT + 3); ForwardSyncStep step = new ForwardSyncStep(context, backwardChain); @@ -173,6 +205,17 @@ public void shouldExecuteForwardSyncWhenPossible() throws Exception { completableFuture.get(); } + @Test + public void shouldExecuteForwardSyncWhenPossibleUsingPeerTaskSystem() throws Exception { + when(syncConfig.isPeerTaskSystemEnabled()).thenReturn(true); + final BackwardChain backwardChain = createBackwardChain(LOCAL_HEIGHT, LOCAL_HEIGHT + 3); + ForwardSyncStep step = new ForwardSyncStep(context, backwardChain); + + final CompletableFuture completableFuture = step.executeAsync(); + + completableFuture.get(); + } + @Test public void shouldNotRequestWhenNull() { ForwardSyncStep phase = new ForwardSyncStep(context, null); @@ -202,6 +245,20 @@ public void shouldFindBlockWhenRequested() throws Exception { .containsExactlyInAnyOrder(getBlockByNumber(LOCAL_HEIGHT + 1)); } + @Test + public void shouldFindBlockWhenRequestedUsingPeerTaskSystem() throws Exception { + when(syncConfig.isPeerTaskSystemEnabled()).thenReturn(true); + ForwardSyncStep step = + new ForwardSyncStep(context, createBackwardChain(LOCAL_HEIGHT + 1, LOCAL_HEIGHT + 3)); + + final CompletableFuture> future = + step.requestBodies(List.of(getBlockByNumber(LOCAL_HEIGHT + 1).getHeader())); + final List blocks = future.get(); + Assertions.assertThat(blocks) + .hasSize(1) + .containsExactlyInAnyOrder(getBlockByNumber(LOCAL_HEIGHT + 1)); + } + private BackwardChain createBackwardChain(final int from, final int until) { BackwardChain chain = backwardChainFromBlock(until); for (int i = until; i > from; --i) { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java index e73d286fb0b..98a8a26dbb7 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; +import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.core.Difficulty; @@ -36,6 +37,7 @@ import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode; import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult; +import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetBodiesFromPeerTask; import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetHeadersFromPeerTask; import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetHeadersFromPeerTaskExecutorAnswer; import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetReceiptsFromPeerTask; @@ -59,6 +61,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; @@ -167,6 +170,21 @@ public void setup(final DataStorageFormat dataStorageFormat) { when(peerTaskExecutor.execute(any(GetHeadersFromPeerTask.class))).thenAnswer(getHeadersAnswer); when(peerTaskExecutor.executeAgainstPeer(any(GetHeadersFromPeerTask.class), any(EthPeer.class))) .thenAnswer(getHeadersAnswer); + + Answer>> getBlockBodiesAnswer = + (invocationOnMock) -> { + GetBodiesFromPeerTask task = invocationOnMock.getArgument(0, GetBodiesFromPeerTask.class); + List blocks = + task.getBlockHeaders().stream() + .map((bh) -> new Block(bh, otherBlockchain.getBlockBody(bh.getBlockHash()).get())) + .collect(Collectors.toList()); + return new PeerTaskExecutorResult>( + Optional.of(blocks), PeerTaskExecutorResponseCode.SUCCESS, Optional.empty()); + }; + when(peerTaskExecutor.execute(any(GetBodiesFromPeerTask.class))) + .thenAnswer(getBlockBodiesAnswer); + when(peerTaskExecutor.executeAgainstPeer(any(GetBodiesFromPeerTask.class), any(EthPeer.class))) + .thenAnswer(getBlockBodiesAnswer); } @AfterEach diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderForkTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderForkTest.java index fb518c305f7..1b3745c5f8f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderForkTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderForkTest.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.eth.sync.fullsync; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -28,6 +29,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; @@ -93,7 +95,8 @@ private ChainDownloader downloader(final SynchronizerConfiguration syncConfig) { syncState, metricsSystem, SyncTerminationCondition.never(), - SyncDurationMetrics.NO_OP_SYNC_DURATION_METRICS); + SyncDurationMetrics.NO_OP_SYNC_DURATION_METRICS, + mock(PeerTaskExecutor.class)); } private ChainDownloader downloader() { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java index 2c3c1ecdc8b..4f2577e497a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryBlockchain; +import static org.mockito.Mockito.mock; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -35,6 +36,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.messages.EthPV62; import org.hyperledger.besu.ethereum.eth.messages.GetBlockHeadersMessage; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; @@ -125,7 +127,8 @@ private ChainDownloader downloader(final SynchronizerConfiguration syncConfig) { syncState, metricsSystem, SyncTerminationCondition.never(), - SyncDurationMetrics.NO_OP_SYNC_DURATION_METRICS); + SyncDurationMetrics.NO_OP_SYNC_DURATION_METRICS, + mock(PeerTaskExecutor.class)); } private ChainDownloader downloader() { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java index d79a2209241..55d96acb1c2 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.eth.sync.fullsync; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -28,6 +29,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; @@ -111,7 +113,8 @@ private ChainDownloader downloader( syncState, metricsSystem, terminalCondition, - SyncDurationMetrics.NO_OP_SYNC_DURATION_METRICS); + SyncDurationMetrics.NO_OP_SYNC_DURATION_METRICS, + mock(PeerTaskExecutor.class)); } private SynchronizerConfiguration.Builder syncConfigBuilder() { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java index f50b7edfcff..3953c75882a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java @@ -100,6 +100,7 @@ private FullSyncDownloader downloader(final SynchronizerConfiguration syncConfig syncState, metricsSystem, SyncTerminationCondition.never(), + null, SyncDurationMetrics.NO_OP_SYNC_DURATION_METRICS); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksWithPeerTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksWithPeerTaskTest.java new file mode 100644 index 00000000000..e2fc9e50744 --- /dev/null +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksWithPeerTaskTest.java @@ -0,0 +1,253 @@ +/* + * Copyright contributors to 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.eth.sync.tasks; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.WithdrawalsProcessor; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class CompleteBlocksWithPeerTaskTest { + + @BeforeAll + public static void setUp() {} + + @Test + public void shouldFailWhenEmptyHeaders() { + assertThatThrownBy(() -> new CompleteBlocksWithPeerTask(null, Collections.emptyList(), null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Must supply a non-empty headers list"); + } + + @Test + public void shouldReturnEmptyBlock() { + final ProtocolSchedule protocolSchedule = getProtocolScheduleMock(); + final BlockHeader blockHeader = getEmptyBlockHeaderMock(); + final PeerTaskExecutor peerTaskExecutor = mock(PeerTaskExecutor.class); + + CompleteBlocksWithPeerTask completeBlocksWithPeerTask = + new CompleteBlocksWithPeerTask(protocolSchedule, List.of(blockHeader), peerTaskExecutor); + final List blocks = completeBlocksWithPeerTask.retrieveBlocksFromPeers(); + assertThat(blocks).isNotEmpty(); + assertThat(blocks.size()).isEqualTo(1); + assertThat(BlockHeader.hasEmptyBlock(blocks.get(0).getHeader())).isTrue(); + + verify(peerTaskExecutor, Mockito.never()).execute(any()); + } + + @Test + public void shouldCreateWithdrawalsAwareEmptyBlock_whenWithdrawalsAreEnabled() { + final ProtocolSchedule mockProtocolSchedule = Mockito.mock(ProtocolSchedule.class); + final ProtocolSpec mockParisSpec = Mockito.mock(ProtocolSpec.class); + final ProtocolSpec mockShanghaiSpec = Mockito.mock(ProtocolSpec.class); + final WithdrawalsProcessor mockWithdrawalsProcessor = Mockito.mock(WithdrawalsProcessor.class); + + final BlockHeader header1 = + new BlockHeaderTestFixture().number(1).withdrawalsRoot(null).buildHeader(); + final BlockHeader header2 = + new BlockHeaderTestFixture().number(2).withdrawalsRoot(Hash.EMPTY_TRIE_HASH).buildHeader(); + + when(mockProtocolSchedule.getByBlockHeader((eq(header1)))).thenReturn(mockParisSpec); + when(mockParisSpec.getWithdrawalsProcessor()).thenReturn(Optional.empty()); + when(mockProtocolSchedule.getByBlockHeader((eq(header2)))).thenReturn(mockShanghaiSpec); + when(mockShanghaiSpec.getWithdrawalsProcessor()) + .thenReturn(Optional.of(mockWithdrawalsProcessor)); + + final List expectedBlocks = getExpectedBlocks(header1, header2); + + final PeerTaskExecutor peerTaskExecutor = mock(PeerTaskExecutor.class); + when(peerTaskExecutor.execute(any())) + .thenReturn( + new PeerTaskExecutorResult<>( + Optional.of(expectedBlocks), + PeerTaskExecutorResponseCode.SUCCESS, + Optional.empty())); + + final CompleteBlocksWithPeerTask task = + new CompleteBlocksWithPeerTask( + mockProtocolSchedule, asList(header1, header2), peerTaskExecutor); + final List blocks = task.retrieveBlocksFromPeers(); + + assertThat(blocks).isEqualTo(expectedBlocks); + } + + @Test + public void shouldReturnNonEmptyBlock() { + final Block block = mock(Block.class); + final ProtocolSchedule protocolSchedule = getProtocolScheduleMock(); + final PeerTaskExecutor peerTaskExecutor = mock(PeerTaskExecutor.class); + final BlockHeader nonEmptyBlockHeaderMock = getNonEmptyBlockHeaderMock("0x01", "0x02"); + when(peerTaskExecutor.execute(any())) + .thenReturn( + new PeerTaskExecutorResult<>( + Optional.of(List.of(block)), + PeerTaskExecutorResponseCode.SUCCESS, + Optional.empty())); + + CompleteBlocksWithPeerTask completeBlocksWithPeerTask = + new CompleteBlocksWithPeerTask( + protocolSchedule, List.of(nonEmptyBlockHeaderMock), peerTaskExecutor); + + final List blocks = completeBlocksWithPeerTask.retrieveBlocksFromPeers(); + assertThat(blocks).isNotEmpty(); + assertThat(blocks.size()).isEqualTo(1); + assertThat(blocks.get(0)).isEqualTo(block); + } + + @Test + public void shouldReturnBlocksInRightOrderWhenEmptyAndNonEmptyBlocksRequested() { + final Block block1 = mock(Block.class); + final Block block3 = mock(Block.class); + final BlockHeader emptyBlockHeaderMock = getEmptyBlockHeaderMock(); + final BlockHeader nonEmptyBlockHeaderMock1 = getNonEmptyBlockHeaderMock("0x01", "0x02"); + final BlockHeader nonEmptyBlockHeaderMock3 = getNonEmptyBlockHeaderMock("0x03", "0x04"); + + final ProtocolSchedule protocolSchedule = getProtocolScheduleMock(); + final PeerTaskExecutor peerTaskExecutor = mock(PeerTaskExecutor.class); + when(peerTaskExecutor.execute(any())) + .thenReturn( + new PeerTaskExecutorResult<>( + Optional.of(List.of(block1, block3)), + PeerTaskExecutorResponseCode.SUCCESS, + Optional.empty())); + + CompleteBlocksWithPeerTask completeBlocksWithPeerTask = + new CompleteBlocksWithPeerTask( + protocolSchedule, + List.of( + nonEmptyBlockHeaderMock1, + emptyBlockHeaderMock, + nonEmptyBlockHeaderMock3, + emptyBlockHeaderMock), + peerTaskExecutor); + + final List blocks = completeBlocksWithPeerTask.retrieveBlocksFromPeers(); + assertThat(blocks).isNotEmpty(); + assertThat(blocks.size()).isEqualTo(4); + assertThat(blocks.get(0)).isEqualTo(block1); + assertThat(BlockHeader.hasEmptyBlock(blocks.get(1).getHeader())).isTrue(); + assertThat(blocks.get(2)).isEqualTo(block3); + assertThat(BlockHeader.hasEmptyBlock(blocks.get(3).getHeader())).isTrue(); + } + + @Test + public void shouldRequestMoreBodiesUntilFinished() { + final Block block1 = mock(Block.class); + final Block block3 = mock(Block.class); + final BlockHeader emptyBlockHeaderMock = getEmptyBlockHeaderMock(); + final BlockHeader nonEmptyBlockHeaderMock1 = getNonEmptyBlockHeaderMock("0x01", "0x02"); + final BlockHeader nonEmptyBlockHeaderMock3 = getNonEmptyBlockHeaderMock("0x03", "0x04"); + + final ProtocolSchedule protocolSchedule = getProtocolScheduleMock(); + final PeerTaskExecutor peerTaskExecutor = mock(PeerTaskExecutor.class); + when(peerTaskExecutor.execute(any())) + .thenReturn( + new PeerTaskExecutorResult<>( + Optional.of(List.of(block1)), + PeerTaskExecutorResponseCode.SUCCESS, + Optional.empty())) + .thenReturn( + new PeerTaskExecutorResult<>( + Optional.of(List.of(block3)), + PeerTaskExecutorResponseCode.SUCCESS, + Optional.empty())); + + CompleteBlocksWithPeerTask completeBlocksWithPeerTask = + new CompleteBlocksWithPeerTask( + protocolSchedule, + List.of( + nonEmptyBlockHeaderMock1, + emptyBlockHeaderMock, + nonEmptyBlockHeaderMock3, + emptyBlockHeaderMock), + peerTaskExecutor); + + final List blocks = completeBlocksWithPeerTask.retrieveBlocksFromPeers(); + assertThat(blocks).isNotEmpty(); + assertThat(blocks.size()).isEqualTo(4); + assertThat(blocks.get(0)).isEqualTo(block1); + assertThat(BlockHeader.hasEmptyBlock(blocks.get(1).getHeader())).isTrue(); + assertThat(blocks.get(2)).isEqualTo(block3); + assertThat(BlockHeader.hasEmptyBlock(blocks.get(3).getHeader())).isTrue(); + } + + private static ProtocolSchedule getProtocolScheduleMock() { + final ProtocolSchedule protocolSchedule = mock(ProtocolSchedule.class); + final ProtocolSpec protocolSpec = mock(ProtocolSpec.class); + final Optional optional = Optional.of(mock(WithdrawalsProcessor.class)); + when(protocolSpec.getWithdrawalsProcessor()).thenReturn(optional); + when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec); + return protocolSchedule; + } + + private static BlockHeader getEmptyBlockHeaderMock() { + final BlockHeader blockHeader = mock(BlockHeader.class); + when(blockHeader.getTransactionsRoot()).thenReturn(Hash.EMPTY_TRIE_HASH); + when(blockHeader.getOmmersHash()).thenReturn(Hash.EMPTY_LIST_HASH); + when(blockHeader.getWithdrawalsRoot()).thenReturn(Optional.empty()); + return blockHeader; + } + + private static BlockHeader getNonEmptyBlockHeaderMock( + final String transactionsRootHexString, final String ommersHash) { + final BlockHeader blockHeader = mock(BlockHeader.class); + when(blockHeader.getTransactionsRoot()) + .thenReturn(Hash.fromHexStringLenient(transactionsRootHexString)); + when(blockHeader.getOmmersHash()).thenReturn(Hash.fromHexStringLenient(ommersHash)); + when(blockHeader.getWithdrawalsRoot()).thenReturn(Optional.empty()); + return blockHeader; + } + + private static List getExpectedBlocks( + final BlockHeader header1, final BlockHeader header2) { + final Block block1 = + new Block( + header1, + new BlockBody(Collections.emptyList(), Collections.emptyList(), Optional.empty())); + final Block block2 = + new Block( + header2, + new BlockBody( + Collections.emptyList(), + Collections.emptyList(), + Optional.of(Collections.emptyList()))); + + return asList(block1, block2); + } +} diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTaskTest.java index f594942afac..ffda7217bb3 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTaskTest.java @@ -26,12 +26,14 @@ import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.eth.manager.EthPeer; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; import org.hyperledger.besu.ethereum.eth.manager.ethtaskutils.RetryingMessageTaskTest; import org.hyperledger.besu.ethereum.eth.manager.exceptions.MaxRetriesReachedException; import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode; import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult; +import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetBodiesFromPeerTask; import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetHeadersFromPeerTask; import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask.PeerTaskResult; import org.hyperledger.besu.ethereum.eth.manager.task.EthTask; @@ -303,6 +305,26 @@ public void marksBadBlockWhenHeaderValidationFailsUsingPeerTaskSystem() { Optional.of(respondingPeer.getEthPeer())); }); + Mockito.when( + peerTaskExecutor.executeAgainstPeer( + Mockito.any(GetBodiesFromPeerTask.class), Mockito.any(EthPeer.class))) + .thenAnswer( + (invocationOnMock) -> { + GetBodiesFromPeerTask task = + invocationOnMock.getArgument(0, GetBodiesFromPeerTask.class); + EthPeer peer = invocationOnMock.getArgument(1, EthPeer.class); + List blocks = + task.getBlockHeaders().stream() + .map( + (blockHeader) -> + new Block( + blockHeader, + blockchain.getBlockBody(blockHeader.getBlockHash()).get())) + .toList(); + return new PeerTaskExecutorResult>( + Optional.of(blocks), PeerTaskExecutorResponseCode.SUCCESS, Optional.of(peer)); + }); + // Execute the task final BlockHeader referenceHeader = chain.get(blockCount - 1).getHeader(); final EthTask> task =