Skip to content

Commit

Permalink
Immediately return empty when state after the head slot is requested. (
Browse files Browse the repository at this point in the history
  • Loading branch information
ajsutton authored May 19, 2022
1 parent c8ff387 commit 8f97fa5
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public StateSelector headSelector() {
return () -> {
final Optional<ChainHead> maybeChainHead = client.getChainHead();
if (maybeChainHead.isEmpty()) {
// Can't have a state past the current chain head.
return SafeFuture.completedFuture(Optional.empty());
}
final ChainHead chainHead = maybeChainHead.get();
Expand Down Expand Up @@ -131,13 +132,17 @@ public StateSelector forSlot(final UInt64 slot) {
client
.getChainHead()
.map(
head ->
client
.getStateAtSlotExact(slot, head.getRoot())
.thenApply(
maybeState ->
maybeState.map(
state -> addMetaData(state, head.isOptimistic(), true))))
head -> {
if (slot.isGreaterThan(head.getSlot())) {
return SafeFuture.completedFuture(Optional.<StateAndMetaData>empty());
}
return client
.getStateAtSlotExact(slot, head.getRoot())
.thenApply(
maybeState ->
maybeState.map(
state -> addMetaData(state, head.isOptimistic(), true)));
})
.orElse(SafeFuture.completedFuture(Optional.empty()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static tech.pegasys.teku.infrastructure.async.SafeFutureAssert.assertThatSafeFuture;
import static tech.pegasys.teku.infrastructure.async.SafeFutureAssert.safeJoin;
import static tech.pegasys.teku.infrastructure.unsigned.UInt64.ZERO;

import java.util.Optional;
import java.util.concurrent.ExecutionException;
import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.Test;
import tech.pegasys.teku.api.exceptions.BadRequestException;
Expand Down Expand Up @@ -52,56 +54,65 @@ public class StateSelectorFactoryTest {
private final StateSelectorFactory factory = new StateSelectorFactory(spec, client);

@Test
public void headSelector_shouldGetBestState() throws ExecutionException, InterruptedException {
public void headSelector_shouldGetBestState() {
final SignedBlockAndState blockAndState = data.randomSignedBlockAndState(10);
final ChainHead chainHead = ChainHead.create(blockAndState);
when(client.getChainHead()).thenReturn(Optional.of(chainHead));
Optional<StateAndMetaData> result = factory.headSelector().getState().get();
Optional<StateAndMetaData> result = safeJoin(factory.headSelector().getState());
assertThat(result).contains(withMetaData(blockAndState.getState()));
}

@Test
public void finalizedSelector_shouldGetFinalizedState()
throws ExecutionException, InterruptedException {
public void finalizedSelector_shouldGetFinalizedState() {
when(client.getLatestFinalized())
.thenReturn(Optional.of(AnchorPoint.fromInitialState(spec, state)));
Optional<StateAndMetaData> result = factory.finalizedSelector().getState().get();
Optional<StateAndMetaData> result = safeJoin(factory.finalizedSelector().getState());
assertThat(result).contains(withMetaData(state));
}

@Test
public void justifiedSelector_shouldGetJustifiedState()
throws ExecutionException, InterruptedException {
public void justifiedSelector_shouldGetJustifiedState() {
when(client.getJustifiedState()).thenReturn(SafeFuture.completedFuture(Optional.of(state)));
Optional<StateAndMetaData> result = factory.justifiedSelector().getState().get();
Optional<StateAndMetaData> result = safeJoin(factory.justifiedSelector().getState());
assertThat(result).contains(withMetaData(state));
verify(client).getJustifiedState();
}

@Test
public void genesisSelector_shouldGetStateAtSlotExact()
throws ExecutionException, InterruptedException {
public void genesisSelector_shouldGetStateAtSlotExact() {
when(client.getStateAtSlotExact(ZERO))
.thenReturn(SafeFuture.completedFuture(Optional.of(state)));
Optional<StateAndMetaData> result = factory.genesisSelector().getState().get();
Optional<StateAndMetaData> result = safeJoin(factory.genesisSelector().getState());
assertThat(result).contains(withMetaData(state));
verify(client).getStateAtSlotExact(ZERO);
}

@Test
public void forSlot_shouldGetStateAtSlotExact() throws ExecutionException, InterruptedException {
final SignedBlockAndState blockAndState = data.randomSignedBlockAndState(15);
public void forSlot_shouldGetStateAtSlotExact() {
final SignedBlockAndState blockAndState =
data.randomSignedBlockAndState(state.getSlot().plus(5));
final ChainHead chainHead = ChainHead.create(blockAndState);
when(client.getChainHead()).thenReturn(Optional.of(chainHead));
when(client.getStateAtSlotExact(state.getSlot(), chainHead.getRoot()))
.thenReturn(SafeFuture.completedFuture(Optional.of(state)));
Optional<StateAndMetaData> result = factory.forSlot(state.getSlot()).getState().get();
Optional<StateAndMetaData> result = safeJoin(factory.forSlot(state.getSlot()).getState());
assertThat(result).contains(withMetaData(state));
}

@Test
public void forStateRoot_shouldGetStateAtSlotExact()
throws ExecutionException, InterruptedException {
public void forSlot_shouldReturnEmptyWhenSlotAfterChainHead() {
final SignedBlockAndState blockAndState = data.randomSignedBlockAndState(15);
final ChainHead chainHead = ChainHead.create(blockAndState);
when(client.getChainHead()).thenReturn(Optional.of(chainHead));
when(client.getStateAtSlotExact(chainHead.getSlot().plus(1), chainHead.getRoot()))
.thenReturn(SafeFuture.completedFuture(Optional.of(state)));
Optional<StateAndMetaData> result = safeJoin(factory.forSlot(state.getSlot()).getState());
assertThat(result).isEmpty();
verify(client, never()).getStateAtSlotExact(any(), any());
}

@Test
public void forStateRoot_shouldGetStateAtSlotExact() {
final Bytes32 blockRoot = BeaconBlockHeader.fromState(state).getRoot();
final SignedBlockAndState head =
data.randomSignedBlockAndState(state.getSlot().plus(3), blockRoot);
Expand All @@ -110,7 +121,8 @@ public void forStateRoot_shouldGetStateAtSlotExact()
when(client.isCanonicalBlock(state.getSlot(), blockRoot, chainHead.getRoot())).thenReturn(true);
when(client.getStateByStateRoot(state.hashTreeRoot()))
.thenReturn(SafeFuture.completedFuture(Optional.of(state)));
Optional<StateAndMetaData> result = factory.forStateRoot(state.hashTreeRoot()).getState().get();
Optional<StateAndMetaData> result =
safeJoin(factory.forStateRoot(state.hashTreeRoot()).getState());
assertThat(result).contains(withMetaData(state));
verify(client).getStateByStateRoot(state.hashTreeRoot());
}
Expand Down

0 comments on commit 8f97fa5

Please sign in to comment.