Skip to content

Commit

Permalink
Merge branch 'main' into debug-trace-with-pipeline
Browse files Browse the repository at this point in the history
  • Loading branch information
ahamlat authored Jan 9, 2025
2 parents 447907b + 8448743 commit 9a5330d
Show file tree
Hide file tree
Showing 21 changed files with 1,015 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1300,14 +1300,14 @@ public Builder versionedHashes(final List<VersionedHash> versionedHashes) {
}

public Builder guessType() {
if (versionedHashes != null && !versionedHashes.isEmpty()) {
if (codeDelegationAuthorizations.isPresent()) {
transactionType = TransactionType.DELEGATE_CODE;
} else if (versionedHashes != null && !versionedHashes.isEmpty()) {
transactionType = TransactionType.BLOB;
} else if (maxPriorityFeePerGas != null || maxFeePerGas != null) {
transactionType = TransactionType.EIP1559;
} else if (accessList.isPresent()) {
transactionType = TransactionType.ACCESS_LIST;
} else if (codeDelegationAuthorizations.isPresent()) {
transactionType = TransactionType.DELEGATE_CODE;
} else {
transactionType = TransactionType.FRONTIER;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,24 @@
*/
package org.hyperledger.besu.ethereum.core;

import static java.util.stream.Collectors.toUnmodifiableSet;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.datatypes.VersionedHash.DEFAULT_VERSIONED_HASH;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;

import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;

import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Stream;

Expand All @@ -45,20 +46,51 @@ class TransactionBuilderTest {
@Test
void guessTypeCanGuessAllTypes() {
final BlockDataGenerator gen = new BlockDataGenerator();
final List<AccessListEntry> accessList =
List.of(new AccessListEntry(gen.address(), List.of(gen.bytes32())));

final Transaction.Builder frontierBuilder = Transaction.builder();
final Transaction.Builder eip1559Builder = Transaction.builder().maxFeePerGas(Wei.of(5));
final Transaction.Builder accessListBuilder =
final Transaction.Builder accessListBuilder = Transaction.builder().accessList(accessList);

final Transaction.Builder eip1559Builder =
Transaction.builder().accessList(accessList).maxFeePerGas(Wei.of(5));

final Transaction.Builder blobBuilder =
Transaction.builder()
.accessList(accessList)
.maxFeePerGas(Wei.of(5))
.versionedHashes(List.of(DEFAULT_VERSIONED_HASH));

final CodeDelegation codeDelegation =
new CodeDelegation(
BigInteger.ZERO,
Address.ZERO,
0,
new SECPSignature(BigInteger.ZERO, BigInteger.ZERO, (byte) 0));

final Transaction.Builder delegateCodeBuilder =
Transaction.builder()
.accessList(List.of(new AccessListEntry(gen.address(), List.of(gen.bytes32()))));
.accessList(accessList)
.maxFeePerGas(Wei.of(5))
.codeDelegations(List.of(codeDelegation));

final Set<TransactionType> guessedTypes =
Stream.of(frontierBuilder, eip1559Builder, accessListBuilder)
final List<TransactionType> guessedTypes =
Stream.of(
frontierBuilder,
accessListBuilder,
eip1559Builder,
blobBuilder,
delegateCodeBuilder)
.map(transactionBuilder -> transactionBuilder.guessType().getTransactionType())
.collect(toUnmodifiableSet());
.toList();

assertThat(guessedTypes)
.containsExactlyInAnyOrder(
TransactionType.FRONTIER, TransactionType.ACCESS_LIST, TransactionType.EIP1559);
.containsExactly(
TransactionType.FRONTIER,
TransactionType.ACCESS_LIST,
TransactionType.EIP1559,
TransactionType.BLOB,
TransactionType.DELEGATE_CODE);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -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<List<Block>> {

private static final Logger LOG = LoggerFactory.getLogger(GetBodiesFromPeerTask.class);

private static final int DEFAULT_RETRIES_AGAINST_OTHER_PEERS = 5;

private final List<BlockHeader> blockHeaders;
private final ProtocolSchedule protocolSchedule;
private final int allowedRetriesAgainstOtherPeers;

private final long requiredBlockchainHeight;
private final List<Block> blocks = new ArrayList<>();
private final boolean isPoS;

public GetBodiesFromPeerTask(
final List<BlockHeader> blockHeaders, final ProtocolSchedule protocolSchedule) {
this(blockHeaders, protocolSchedule, DEFAULT_RETRIES_AGAINST_OTHER_PEERS);
}

public GetBodiesFromPeerTask(
final List<BlockHeader> 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<Block> 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<BlockBody> 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<EthPeer> getPeerRequirementFilter() {
return (ethPeer) ->
isPoS || ethPeer.chainState().getEstimatedHeight() >= requiredBlockchainHeight;
}

@Override
public PeerTaskValidationResponse validateResult(final List<Block> result) {
if (result.isEmpty()) {
return PeerTaskValidationResponse.NO_RESULTS_RETURNED;
}
return PeerTaskValidationResponse.RESULTS_VALID_AND_GOOD;
}

public List<BlockHeader> getBlockHeaders() {
return blockHeaders;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ public DefaultSynchronizer(
syncState,
metricsSystem,
terminationCondition,
peerTaskExecutor,
syncDurationMetrics));

if (SyncMode.FAST.equals(syncConfig.getSyncMode())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<List<Block>> apply(final List<BlockHeader> 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<List<Block>> getBodiesWithPeerTaskSystem(
final List<BlockHeader> headers) {

final CompleteBlocksWithPeerTask completeBlocksWithPeerTask =
new CompleteBlocksWithPeerTask(protocolSchedule, headers, ethContext.getPeerTaskExecutor());
final List<Block> blocks = completeBlocksWithPeerTask.retrieveBlocksFromPeers();
return CompletableFuture.completedFuture(blocks);
}
}
Loading

0 comments on commit 9a5330d

Please sign in to comment.