|
|
@ -17,6 +17,9 @@ package org.hyperledger.besu.ethereum.eth.sync.snapsync; |
|
|
|
import static org.assertj.core.api.Assertions.assertThat; |
|
|
|
import static org.assertj.core.api.Assertions.assertThat; |
|
|
|
import static org.assertj.core.api.Assertions.fail; |
|
|
|
import static org.assertj.core.api.Assertions.fail; |
|
|
|
import static org.mockito.Mockito.mock; |
|
|
|
import static org.mockito.Mockito.mock; |
|
|
|
|
|
|
|
import static org.mockito.Mockito.spy; |
|
|
|
|
|
|
|
import static org.mockito.Mockito.times; |
|
|
|
|
|
|
|
import static org.mockito.Mockito.verify; |
|
|
|
import static org.mockito.Mockito.when; |
|
|
|
import static org.mockito.Mockito.when; |
|
|
|
|
|
|
|
|
|
|
|
import org.hyperledger.besu.datatypes.Hash; |
|
|
|
import org.hyperledger.besu.datatypes.Hash; |
|
|
@ -25,12 +28,15 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.AccountRangeDataR |
|
|
|
import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.BytecodeRequest; |
|
|
|
import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.BytecodeRequest; |
|
|
|
import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; |
|
|
|
import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; |
|
|
|
import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.StorageRangeDataRequest; |
|
|
|
import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.StorageRangeDataRequest; |
|
|
|
|
|
|
|
import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.AccountTrieNodeHealingRequest; |
|
|
|
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage; |
|
|
|
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage; |
|
|
|
import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; |
|
|
|
import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; |
|
|
|
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; |
|
|
|
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; |
|
|
|
|
|
|
|
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; |
|
|
|
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; |
|
|
|
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; |
|
|
|
import org.hyperledger.besu.services.tasks.Task; |
|
|
|
import org.hyperledger.besu.services.tasks.Task; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import java.util.Collections; |
|
|
|
import java.util.List; |
|
|
|
import java.util.List; |
|
|
|
|
|
|
|
|
|
|
|
import org.apache.tuweni.bytes.Bytes; |
|
|
|
import org.apache.tuweni.bytes.Bytes; |
|
|
@ -39,9 +45,12 @@ import org.junit.jupiter.api.Test; |
|
|
|
|
|
|
|
|
|
|
|
public class PersistDataStepTest { |
|
|
|
public class PersistDataStepTest { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final WorldStateKeyValueStorage worldStateKeyValueStorage = |
|
|
|
|
|
|
|
spy( |
|
|
|
|
|
|
|
new InMemoryKeyValueStorageProvider() |
|
|
|
|
|
|
|
.createWorldStateStorage(DataStorageConfiguration.DEFAULT_CONFIG)); |
|
|
|
private final WorldStateStorageCoordinator worldStateStorageCoordinator = |
|
|
|
private final WorldStateStorageCoordinator worldStateStorageCoordinator = |
|
|
|
new InMemoryKeyValueStorageProvider() |
|
|
|
new WorldStateStorageCoordinator(worldStateKeyValueStorage); |
|
|
|
.createWorldStateStorageCoordinator(DataStorageConfiguration.DEFAULT_CONFIG); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final SnapSyncProcessState snapSyncState = mock(SnapSyncProcessState.class); |
|
|
|
private final SnapSyncProcessState snapSyncState = mock(SnapSyncProcessState.class); |
|
|
|
private final SnapWorldDownloadState downloadState = mock(SnapWorldDownloadState.class); |
|
|
|
private final SnapWorldDownloadState downloadState = mock(SnapWorldDownloadState.class); |
|
|
@ -67,6 +76,33 @@ public class PersistDataStepTest { |
|
|
|
assertDataPersisted(tasks); |
|
|
|
assertDataPersisted(tasks); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
public void shouldPersistTrieNodeHealDataOnlyOnce() { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final Bytes stateTrieNode = |
|
|
|
|
|
|
|
Bytes.fromHexString( |
|
|
|
|
|
|
|
"0xe2a0310e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf602"); |
|
|
|
|
|
|
|
final Hash hash = Hash.hash(stateTrieNode); |
|
|
|
|
|
|
|
final Bytes location = Bytes.of(0x02); |
|
|
|
|
|
|
|
final AccountTrieNodeHealingRequest accountTrieNodeDataRequest = |
|
|
|
|
|
|
|
SnapDataRequest.createAccountTrieNodeDataRequest(hash, location, Collections.emptySet()); |
|
|
|
|
|
|
|
accountTrieNodeDataRequest.setData(stateTrieNode); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final BonsaiWorldStateKeyValueStorage.Updater updater = |
|
|
|
|
|
|
|
(BonsaiWorldStateKeyValueStorage.Updater) spy(worldStateKeyValueStorage.updater()); |
|
|
|
|
|
|
|
when(worldStateKeyValueStorage.updater()) |
|
|
|
|
|
|
|
.thenReturn(updater) |
|
|
|
|
|
|
|
.thenReturn(mock(BonsaiWorldStateKeyValueStorage.Updater.class)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<Task<SnapDataRequest>> result = |
|
|
|
|
|
|
|
persistDataStep.persist(List.of(new StubTask(accountTrieNodeDataRequest))); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
persistDataStep.persist(List.of(new StubTask(accountTrieNodeDataRequest))); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
verify(updater, times(1)).putAccountStateTrieNode(location, hash, stateTrieNode); |
|
|
|
|
|
|
|
assertDataPersisted(result); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
public void shouldSkipPersistDataWhenNoData() { |
|
|
|
public void shouldSkipPersistDataWhenNoData() { |
|
|
|
final List<Task<SnapDataRequest>> tasks = TaskGenerator.createAccountRequest(false); |
|
|
|
final List<Task<SnapDataRequest>> tasks = TaskGenerator.createAccountRequest(false); |
|
|
@ -110,6 +146,14 @@ public class PersistDataStepTest { |
|
|
|
.getStrategy(BonsaiWorldStateKeyValueStorage.class) |
|
|
|
.getStrategy(BonsaiWorldStateKeyValueStorage.class) |
|
|
|
.getCode(Hash.wrap(data.getCodeHash()), Hash.wrap(data.getAccountHash()))) |
|
|
|
.getCode(Hash.wrap(data.getCodeHash()), Hash.wrap(data.getAccountHash()))) |
|
|
|
.isPresent(); |
|
|
|
.isPresent(); |
|
|
|
|
|
|
|
} else if (task.getData() instanceof AccountTrieNodeHealingRequest) { |
|
|
|
|
|
|
|
final AccountTrieNodeHealingRequest data = |
|
|
|
|
|
|
|
(AccountTrieNodeHealingRequest) task.getData(); |
|
|
|
|
|
|
|
assertThat( |
|
|
|
|
|
|
|
worldStateStorageCoordinator |
|
|
|
|
|
|
|
.getStrategy(BonsaiWorldStateKeyValueStorage.class) |
|
|
|
|
|
|
|
.getTrieNodeUnsafe(data.getLocation())) |
|
|
|
|
|
|
|
.isPresent(); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
fail("not expected message"); |
|
|
|
fail("not expected message"); |
|
|
|
} |
|
|
|
} |
|
|
|