diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d7730f0e3c..09e2439489b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ - In JSON-RPC return optional `v` fields for type 1 and type 2 transactions [#6762](https://github.com/hyperledger/besu/pull/6762) - Fix Shanghai/QBFT block import bug when syncing new nodes [#6765](https://github.com/hyperledger/besu/pull/6765) - Fix to avoid broadcasting full blob txs, instead of only the tx announcement, to a subset of nodes [#6835](https://github.com/hyperledger/besu/pull/6835) +- Snap client fixes discovered during snap server testing [#6847](https://github.com/hyperledger/besu/pull/6847) ### Download Links diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 1c63329ac25..26422b0f660 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1554,7 +1554,7 @@ private void ensureValidPeerBoundParams() { checkState( fraction >= 0.0 && fraction <= 1.0, "Fraction of remote connections allowed must be between 0.0 and 1.0 (inclusive)."); - maxRemoteInitiatedPeers = (int) Math.floor(fraction * maxPeers); + maxRemoteInitiatedPeers = Math.round(fraction * maxPeers); } else { maxRemoteInitiatedPeers = maxPeers; } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RequestDataStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RequestDataStep.java index adbb8b736c1..f866f4c41ba 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RequestDataStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RequestDataStep.java @@ -41,6 +41,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.NavigableMap; import java.util.TreeMap; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -49,9 +50,11 @@ import kotlin.collections.ArrayDeque; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class RequestDataStep { - + private static final Logger LOG = LoggerFactory.getLogger(RequestDataStep.class); private final WorldStateStorageCoordinator worldStateStorageCoordinator; private final SnapSyncProcessState fastSyncState; private final SnapWorldDownloadState downloadState; @@ -131,15 +134,36 @@ public CompletableFuture>> requestStorage( (response, error) -> { if (response != null) { downloadState.removeOutstandingTask(getStorageRangeTask); - for (int i = 0; i < response.slots().size(); i++) { - final StorageRangeDataRequest request = - (StorageRangeDataRequest) requestTasks.get(i).getData(); - request.setRootHash(blockHeader.getStateRoot()); - request.addResponse( - downloadState, - worldStateProofProvider, - response.slots().get(i), - i < response.slots().size() - 1 ? new ArrayDeque<>() : response.proofs()); + final ArrayDeque> slots = new ArrayDeque<>(); + // Check if we have an empty range + + /* + * Checks if the response represents an "empty range". + * + * An "empty range" is defined as a response where at least one proof exists + * and either no slots are present, or the first slot is empty + */ + try { + final boolean isEmptyRange = + (response.slots().isEmpty() || response.slots().get(0).isEmpty()) + && !response.proofs().isEmpty(); + if (isEmptyRange) { // empty range detected + slots.add(new TreeMap<>()); + } else { + slots.addAll(response.slots()); + } + for (int i = 0; i < slots.size(); i++) { + final StorageRangeDataRequest request = + (StorageRangeDataRequest) requestTasks.get(i).getData(); + request.setRootHash(blockHeader.getStateRoot()); + request.addResponse( + downloadState, + worldStateProofProvider, + slots.get(i), + i < slots.size() - 1 ? new ArrayDeque<>() : response.proofs()); + } + } catch (final Exception e) { + LOG.error("Error while processing storage range response", e); } } return requestTasks; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrie.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrie.java index 1cf593665a0..7221c8da4fa 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrie.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrie.java @@ -114,6 +114,10 @@ public void commit(final FlatDatabaseUpdater flatDatabaseUpdater, final NodeUpda keys.putAll(taskElement.keys()); }); + if (keys.isEmpty()) { + return; // empty range we can ignore it + } + final Map proofsEntries = new HashMap<>(); for (Bytes proof : proofs) { proofsEntries.put(Hash.hash(proof), proof);