diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java index 4c50926303..c405e2525e 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java @@ -179,6 +179,10 @@ public class StorageRangeDataRequest extends SnapDataRequest { final StackTrie.TaskElement taskElement = stackTrie.getElement(startKeyHash); + if (null == taskElement) { + return Stream.empty(); + } + findNewBeginElementInRange(storageRoot, taskElement.proofs(), taskElement.keys(), endKeyHash) .ifPresent( missingRightElement -> { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageHandler.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageHandler.java index ab909eada1..f2e9378fd4 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageHandler.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageHandler.java @@ -45,11 +45,11 @@ class NewPooledTransactionHashesMessageHandler implements EthMessages.MessageCal @Override public void exec(final EthMessage message) { - final Capability capability = message.getPeer().getConnection().capability(EthProtocol.NAME); - final NewPooledTransactionHashesMessage transactionsMessage = - NewPooledTransactionHashesMessage.readFrom(message.getData(), capability); - final Instant startedAt = now(); if (isEnabled.get()) { + final Capability capability = message.getPeer().getConnection().capability(EthProtocol.NAME); + final NewPooledTransactionHashesMessage transactionsMessage = + NewPooledTransactionHashesMessage.readFrom(message.getData(), capability); + final Instant startedAt = now(); scheduler.scheduleTxWorkerTask( () -> transactionsMessageProcessor.processNewPooledTransactionHashesMessage( diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageHandler.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageHandler.java index 3160d1a9c5..b6bbf442da 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageHandler.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageHandler.java @@ -43,9 +43,10 @@ class TransactionsMessageHandler implements EthMessages.MessageCallback { @Override public void exec(final EthMessage message) { - final TransactionsMessage transactionsMessage = TransactionsMessage.readFrom(message.getData()); - final Instant startedAt = now(); if (isEnabled.get()) { + final TransactionsMessage transactionsMessage = + TransactionsMessage.readFrom(message.getData()); + final Instant startedAt = now(); scheduler.scheduleTxWorkerTask( () -> transactionsMessageProcessor.processTransactionsMessage( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/CompleteTaskStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/CompleteTaskStepTest.java index 2bfc58a3b8..b78f2b10e8 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/CompleteTaskStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/CompleteTaskStepTest.java @@ -116,7 +116,7 @@ public class CompleteTaskStepTest { @Test public void shouldMarkSnapsyncTaskCompleteWhenData() { - final List> requests = TaskGenerator.createAccountRequest(true); + final List> requests = TaskGenerator.createAccountRequest(true, false); requests.stream() .map(StubTask.class::cast) .forEach( @@ -132,7 +132,7 @@ public class CompleteTaskStepTest { @Test public void shouldMarkSnapsyncTaskAsFailedWhenNoData() { - final List> requests = TaskGenerator.createAccountRequest(false); + final List> requests = TaskGenerator.createAccountRequest(false, false); requests.stream() .map(StubTask.class::cast) .forEach( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java index 766995b094..963293be0c 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java @@ -68,7 +68,7 @@ public class PersistDataStepTest { @Test public void shouldPersistDataWhenPresent() { - final List> tasks = TaskGenerator.createAccountRequest(true); + final List> tasks = TaskGenerator.createAccountRequest(true, false); final List> result = persistDataStep.persist(tasks); assertThat(result).isSameAs(tasks); @@ -105,7 +105,7 @@ public class PersistDataStepTest { @Test public void shouldSkipPersistDataWhenNoData() { - final List> tasks = TaskGenerator.createAccountRequest(false); + final List> tasks = TaskGenerator.createAccountRequest(false, false); final List> result = persistDataStep.persist(tasks); assertThat(result).isSameAs(tasks); @@ -116,6 +116,25 @@ public class PersistDataStepTest { .isEmpty(); } + @Test + public void shouldHandleNullTaskElementInTrie() { + // Create a StorageRangeDataRequest where taskElement might be null or incomplete + List> tasks = TaskGenerator.createAccountRequest(false, true); + + try { + List> result = persistDataStep.persist(tasks); + + // check for proper handling of null taskElement + assertThat(result).isSameAs(tasks); + assertThat(result) + .isNotNull(); // Make sure the result isn't null even with the bad taskElement + } catch (NullPointerException e) { + fail( + "NullPointerException occurred during persist step, taskElement might be null: " + + e.getMessage()); + } + } + private void assertDataPersisted(final List> tasks) { tasks.forEach( task -> { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java index 0e3915bc77..0b3a17cccf 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java @@ -44,7 +44,8 @@ import org.apache.tuweni.bytes.Bytes32; public class TaskGenerator { - public static List> createAccountRequest(final boolean withData) { + public static List> createAccountRequest( + final boolean withData, final boolean withNullTaskElement) { final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage = new BonsaiWorldStateKeyValueStorage( @@ -91,7 +92,8 @@ public class TaskGenerator { rootHash, accountHash, stateTrieAccountValue.getStorageRoot(), - withData); + withData, + withNullTaskElement); final BytecodeRequest bytecodeRequest = createBytecodeDataRequest( worldStateKeyValueStorage, @@ -112,7 +114,8 @@ public class TaskGenerator { final Hash rootHash, final Hash accountHash, final Bytes32 storageRoot, - final boolean withData) { + final boolean withData, + final boolean withNullTaskElement) { final RangeStorageEntriesCollector collector = RangeStorageEntriesCollector.createCollector( @@ -140,6 +143,11 @@ public class TaskGenerator { request.setProofValid(true); request.addResponse(null, worldStateProofProvider, slots, new ArrayDeque<>()); } + + if (withNullTaskElement) { + // setting isValidProof to true to simulate a null task element. + request.setProofValid(true); + } return request; }