Skip to content

Commit

Permalink
add CLI params
Browse files Browse the repository at this point in the history
implemented tests
  • Loading branch information
tbenr committed Aug 18, 2022
1 parent 2bdaf84 commit 8ba53d2
Show file tree
Hide file tree
Showing 9 changed files with 396 additions and 122 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ public SafeFuture<BeaconBlock> createUnsignedBlock(
blockSlotState.getSlot(),
newSlot);

System.out.println("****** newSlot " + newSlot);
System.out.println("****** blockSlotState slot " + blockSlotState.getSlot());
System.out.println(
"****** blockSlotState getLatestBlockHeader slot "
+ blockSlotState.getLatestBlockHeader().getSlot());

// Process empty slots up to the one before the new block slot
final UInt64 slotBeforeBlock = newSlot.minus(UInt64.ONE);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,20 @@ public BuilderCircuitBreakerImpl(

@Override
public boolean isEngaged(final BeaconState state) {
try {
if (getLatestUniqueBlockRootsCount(state) <= minimumUniqueBlockRootsInWindow) {
return true;
}
} catch (Exception ex) {
LOG.error("Builder circuit breaker check failed. Acting like it has been engaged.", ex);

final int uniqueBlockRootsCount = getLatestUniqueBlockRootsCount(state);
if (uniqueBlockRootsCount < minimumUniqueBlockRootsInWindow) {
LOG.debug(
"Builder circuit breaker engaged: slot: {}, uniqueBlockRootsCount: {}, window: {}, minimumUniqueBlockRootsInWindow: {}",
state.getSlot(),
uniqueBlockRootsCount,
faultInspectionWindow,
minimumUniqueBlockRootsInWindow);
return true;
}

LOG.debug("Builder circuit breaker has not engaged.");

return false;
}

Expand All @@ -68,29 +73,33 @@ int getLatestUniqueBlockRootsCount(final BeaconState state) throws IllegalArgume
final HashSet<Bytes32> uniqueBlockRoots = new HashSet<>();
final SszBytes32Vector blockRoots = state.getBlockRoots();

// we subtract 1 because blockRoots refers to previous block
// current is getLatestBlockHeader
final UInt64 firstSlotOfInspectionWindow =
state.getSlot().minusMinZero(faultInspectionWindow - 1);
// state slot is the slot we are building for
// thus our fault window will be (inclusive)
// FROM (state_slot-1)-(faultInspectionWindow-1) TO state_slot-1

// of which:
// state_slot-1 -> will be represented by getLatestBlockHeader
// FROM (state_slot-1)-(faultInspectionWindow-1) TO state_slot-2 -> to be found in blockRoots

// (state_slot-1)-(faultInspectionWindow-1) = state_slot-faultInspectionWindow
final UInt64 firstSlotOfInspectionWindow = state.getSlot().minusMinZero(faultInspectionWindow);
final UInt64 lastSlotOfInspectionWindow = state.getSlot().minusMinZero(1);

// if getLatestBlockHeader is outside the fault window,
// we have definitely missed all blocks so count will be 0
if (state.getLatestBlockHeader().getSlot().isLessThan(firstSlotOfInspectionWindow)) {
return 0;
}

uniqueBlockRoots.add(state.getLatestBlockHeader().getRoot());

UInt64 currentSlot = firstSlotOfInspectionWindow;
while (currentSlot.isLessThan(state.getSlot())) {
while (currentSlot.isLessThan(lastSlotOfInspectionWindow)) {
final int currentBlockRootIndex = currentSlot.mod(slotsPerHistoricalRoot).intValue();
uniqueBlockRoots.add(blockRoots.getElement(currentBlockRootIndex));
currentSlot = currentSlot.increment();
}

// we add getLatestBlockHeader only if it's slot fall into the window
// otherwise we remove it from the count
if (state
.getLatestBlockHeader()
.getSlot()
.isGreaterThanOrEqualTo(firstSlotOfInspectionWindow)) {
uniqueBlockRoots.add(state.getLatestBlockHeader().getRoot());
} else {
uniqueBlockRoots.remove(state.getLatestBlockHeader().getRoot());
}

return uniqueBlockRoots.size();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ public SafeFuture<ExecutionPayloadHeader> builderGetHeader(
fallbackReason = FallbackReason.NOT_NEEDED;
} else if (isTransitionNotFinalized(executionPayloadContext)) {
fallbackReason = FallbackReason.TRANSITION_NOT_FINALIZED;
} else if (builderCircuitBreaker.isEngaged(state)) {
} else if (isCircuitBreakerEngaged(state)) {
fallbackReason = FallbackReason.CIRCUIT_BREAKER_ENGAGED;
} else if (builderClient.isEmpty()) {
fallbackReason = FallbackReason.BUILDER_NOT_CONFIGURED;
Expand Down Expand Up @@ -528,6 +528,15 @@ private boolean isTransitionNotFinalized(final ExecutionPayloadContext execution
return executionPayloadContext.getForkChoiceState().getFinalizedExecutionBlockHash().isZero();
}

private boolean isCircuitBreakerEngaged(final BeaconState state) {
try {
return builderCircuitBreaker.isEngaged(state);
} catch (Exception ex) {
LOG.error("Builder circuit breaker engagement failure. Acting like it has been engaged.", ex);
return true;
}
}

private void markBuilderAsNotAvailable(final String errorMessage) {
latestBuilderAvailability.set(false);
eventLogger.builderIsOffline(errorMessage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import tech.pegasys.teku.infrastructure.ssz.collections.SszBytes32Vector;
import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszBytes32VectorSchema;
Expand All @@ -41,10 +42,18 @@ public class BuilderCircuitBreakerImplTest {
private static final int INSPECTION_WINDOW = 10;
private static final int ALLOWED_FAULTS = 5;

@Test
@BeforeEach
void check() {
// all tests assume 64 block roots history
assertThat(spec.getGenesisSpec().getSlotsPerHistoricalRoot()).isEqualTo(64);
}

@Test
void shouldNotEngage_noMissedSlots() {
final UInt64 slot = UInt64.valueOf(spec.getGenesisSpec().getSlotsPerHistoricalRoot() + 5);
final UInt64 slot = UInt64.valueOf(100);

// fill blockRoots with random roots and have a different latestBlockHeader root too
final List<Bytes32> blockRoots =
Stream.generate(dataStructureUtil::randomBytes32)
.limit(spec.getGenesisSpec().getSlotsPerHistoricalRoot())
Expand All @@ -58,7 +67,122 @@ void shouldNotEngage_noMissedSlots() {
}

@Test
void shouldNotEngage_minimalAllowedFaults() {}
void shouldNotEngage_minimalAllowedFaults() {
final UInt64 stateSlot = UInt64.valueOf(69);

final BeaconBlock latestBlock = dataStructureUtil.randomBeaconBlock(68);
final BeaconBlockHeader latestBlockHeader = BeaconBlockHeader.fromBlock(latestBlock);

// fill blockRoots [59-63] with 2 unique roots
// fill blockRoots [0-3] (slot 64 to 67) with 2 unique roots
// a different latestBlockHeader root too (slot 68)
// for a total of 5 unique

final List<Bytes32> uniqueRoots =
Stream.generate(dataStructureUtil::randomBytes32).limit(4).collect(Collectors.toList());

final List<Bytes32> blockRoots =
Stream.concat(
// 4 elements - from slot 64 to 67
Stream.of(
uniqueRoots.get(0), uniqueRoots.get(1), uniqueRoots.get(0), uniqueRoots.get(1)),
Stream.concat(
// 55 elements
Stream.generate(() -> Bytes32.ZERO)
.limit(spec.getGenesisSpec().getSlotsPerHistoricalRoot() - 9),
// 5 elements - from slot 59 to 63
Stream.of(
uniqueRoots.get(2),
uniqueRoots.get(3),
uniqueRoots.get(2),
uniqueRoots.get(3),
uniqueRoots.get(2))))
.collect(Collectors.toList());
final BeaconState state = prepareState(stateSlot, latestBlockHeader, blockRoots);

assertThat(builderCircuitBreaker.isEngaged(state)).isFalse();
assertThat(builderCircuitBreaker.getLatestUniqueBlockRootsCount(state)).isEqualTo(5);
}

@Test
void shouldEngage_belowAllowedFaults() {
final UInt64 stateSlot = UInt64.valueOf(69);

final BeaconBlock latestBlock = dataStructureUtil.randomBeaconBlock(67);
final BeaconBlockHeader latestBlockHeader = BeaconBlockHeader.fromBlock(latestBlock);

// fill blockRoots [59-63] with 2 unique roots
// fill blockRoots [0-3] (slot 64 to 67) with 2 unique roots
// latestBlockHeader same as slot 67
// for a total of 4 unique

final List<Bytes32> uniqueRoots =
Stream.generate(dataStructureUtil::randomBytes32).limit(4).collect(Collectors.toList());

final List<Bytes32> blockRoots =
Stream.concat(
// 4 elements - from slot 64 to 67
Stream.of(
uniqueRoots.get(0),
uniqueRoots.get(0),
uniqueRoots.get(0),
latestBlockHeader.getRoot()),
Stream.concat(
// 55 elements
Stream.generate(() -> Bytes32.ZERO)
.limit(spec.getGenesisSpec().getSlotsPerHistoricalRoot() - 9),
// 5 elements - from slot 59 to 63
Stream.of(
uniqueRoots.get(2),
uniqueRoots.get(3),
uniqueRoots.get(2),
uniqueRoots.get(3),
uniqueRoots.get(2))))
.collect(Collectors.toList());

final BeaconState state = prepareState(stateSlot, latestBlockHeader, blockRoots);

assertThat(builderCircuitBreaker.isEngaged(state)).isTrue();
assertThat(builderCircuitBreaker.getLatestUniqueBlockRootsCount(state)).isEqualTo(4);
}

@Test
void shouldEngage_belowAllowedFaults_onlyLastBlockHeaderPresent() {
final UInt64 stateSlot = UInt64.valueOf(69);

final BeaconBlock latestBlock = dataStructureUtil.randomBeaconBlock(59);
final BeaconBlockHeader latestBlockHeader = BeaconBlockHeader.fromBlock(latestBlock);

// fill blockRoots with random roots and have a different latestBlockHeader root too
final List<Bytes32> blockRoots =
Stream.generate(latestBlockHeader::getRoot)
.limit(spec.getGenesisSpec().getSlotsPerHistoricalRoot())
.collect(Collectors.toList());

final BeaconState state = prepareState(stateSlot, latestBlockHeader, blockRoots);

assertThat(builderCircuitBreaker.isEngaged(state)).isTrue();
assertThat(builderCircuitBreaker.getLatestUniqueBlockRootsCount(state)).isEqualTo(1);
}

@Test
void shouldEngage_belowAllowedFaults_lastBlockHeaderWellOff() {
final UInt64 stateSlot = UInt64.valueOf(69);

final BeaconBlock latestBlock = dataStructureUtil.randomBeaconBlock(40);
final BeaconBlockHeader latestBlockHeader = BeaconBlockHeader.fromBlock(latestBlock);

// fill blockRoots with random roots and have a different latestBlockHeader root too
final List<Bytes32> blockRoots =
Stream.generate(latestBlockHeader::getRoot)
.limit(spec.getGenesisSpec().getSlotsPerHistoricalRoot())
.collect(Collectors.toList());

final BeaconState state = prepareState(stateSlot, latestBlockHeader, blockRoots);

assertThat(builderCircuitBreaker.isEngaged(state)).isTrue();
assertThat(builderCircuitBreaker.getLatestUniqueBlockRootsCount(state)).isEqualTo(0);
}

private BeaconState prepareState(
final UInt64 slot,
Expand Down
Loading

0 comments on commit 8ba53d2

Please sign in to comment.