Skip to content

Commit

Permalink
Apply proposer boost to first block in case of equivocation (Consensy…
Browse files Browse the repository at this point in the history
  • Loading branch information
StefanBratanov authored Sep 21, 2023
1 parent d64fd19 commit 9f169a8
Showing 9 changed files with 151 additions and 97 deletions.
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static tech.pegasys.teku.infrastructure.async.SafeFutureAssert.safeJoin;
import static tech.pegasys.teku.infrastructure.time.TimeUtilities.secondsToMillis;
import static tech.pegasys.teku.networks.Eth2NetworkConfiguration.DEFAULT_FORK_CHOICE_PROPOSER_BOOST_UNIQUENESS_ENABLED;
import static tech.pegasys.teku.networks.Eth2NetworkConfiguration.DEFAULT_FORK_CHOICE_UPDATE_HEAD_ON_BLOCK_IMPORT_ENABLED;

import com.google.common.collect.ImmutableMap;
@@ -128,6 +129,7 @@ spec, new SignedBlockAndState(anchorBlock, anchorState)),
new TickProcessor(spec, recentChainData),
transitionBlockValidator,
DEFAULT_FORK_CHOICE_UPDATE_HEAD_ON_BLOCK_IMPORT_ENABLED,
DEFAULT_FORK_CHOICE_PROPOSER_BOOST_UNIQUENESS_ENABLED,
storageSystem.getMetricsSystem());
final ExecutionLayerChannelStub executionLayer =
new ExecutionLayerChannelStub(spec, false, Optional.empty());
Original file line number Diff line number Diff line change
@@ -60,37 +60,21 @@ public Spec getSpec() {
}

private void createSpec() {
final Eth2Network network;
final SpecMilestone highestSupportedMilestone;
switch (configName) {
case TestSpecConfig.MAINNET:
network = Eth2Network.MAINNET;
break;
case TestSpecConfig.MINIMAL:
network = Eth2Network.MINIMAL;
break;
default:
throw new IllegalArgumentException("Unknown configName: " + configName);
}
switch (fork) {
case TestFork.PHASE0:
highestSupportedMilestone = SpecMilestone.PHASE0;
break;
case TestFork.ALTAIR:
highestSupportedMilestone = SpecMilestone.ALTAIR;
break;
case TestFork.BELLATRIX:
highestSupportedMilestone = SpecMilestone.BELLATRIX;
break;
case TestFork.CAPELLA:
highestSupportedMilestone = SpecMilestone.CAPELLA;
break;
case TestFork.DENEB:
highestSupportedMilestone = SpecMilestone.DENEB;
break;
default:
throw new IllegalArgumentException("Unknown fork: " + fork);
}
final Eth2Network network =
switch (configName) {
case TestSpecConfig.MAINNET -> Eth2Network.MAINNET;
case TestSpecConfig.MINIMAL -> Eth2Network.MINIMAL;
default -> throw new IllegalArgumentException("Unknown configName: " + configName);
};
final SpecMilestone highestSupportedMilestone =
switch (fork) {
case TestFork.PHASE0 -> SpecMilestone.PHASE0;
case TestFork.ALTAIR -> SpecMilestone.ALTAIR;
case TestFork.BELLATRIX -> SpecMilestone.BELLATRIX;
case TestFork.CAPELLA -> SpecMilestone.CAPELLA;
case TestFork.DENEB -> SpecMilestone.DENEB;
default -> throw new IllegalArgumentException("Unknown fork: " + fork);
};
spec = TestSpecFactory.create(highestSupportedMilestone, network);
}

Original file line number Diff line number Diff line change
@@ -48,6 +48,7 @@ public class Eth2NetworkConfiguration {
private static final int DEFAULT_STARTUP_TIMEOUT_SECONDS = 30;

public static final boolean DEFAULT_FORK_CHOICE_UPDATE_HEAD_ON_BLOCK_IMPORT_ENABLED = false;
public static final boolean DEFAULT_FORK_CHOICE_PROPOSER_BOOST_UNIQUENESS_ENABLED = false;

public static final String INITIAL_STATE_URL_PATH = "eth/v2/debug/beacon/states/finalized";
// 26 thousand years should be enough
@@ -70,6 +71,7 @@ public class Eth2NetworkConfiguration {
private final Optional<String> trustedSetup;

private final boolean forkChoiceUpdateHeadOnBlockImportEnabled;
private final boolean forkChoiceProposerBoostUniquenessEnabled;
private final Optional<Bytes32> terminalBlockHashOverride;
private final Optional<UInt256> totalTerminalDifficultyOverride;
private final Optional<UInt64> terminalBlockHashEpochOverride;
@@ -89,6 +91,7 @@ private Eth2NetworkConfiguration(
final Optional<UInt64> eth1DepositContractDeployBlock,
final Optional<String> trustedSetup,
final boolean forkChoiceUpdateHeadOnBlockImportEnabled,
final boolean forkChoiceProposerBoostUniquenessEnabled,
final Optional<UInt64> altairForkEpoch,
final Optional<UInt64> bellatrixForkEpoch,
final Optional<UInt64> capellaForkEpoch,
@@ -117,6 +120,7 @@ private Eth2NetworkConfiguration(
this.eth1DepositContractDeployBlock = eth1DepositContractDeployBlock;
this.trustedSetup = trustedSetup;
this.forkChoiceUpdateHeadOnBlockImportEnabled = forkChoiceUpdateHeadOnBlockImportEnabled;
this.forkChoiceProposerBoostUniquenessEnabled = forkChoiceProposerBoostUniquenessEnabled;
this.terminalBlockHashOverride = terminalBlockHashOverride;
this.totalTerminalDifficultyOverride = totalTerminalDifficultyOverride;
this.terminalBlockHashEpochOverride = terminalBlockHashEpochOverride;
@@ -189,6 +193,10 @@ public boolean isForkChoiceUpdateHeadOnBlockImportEnabled() {
return forkChoiceUpdateHeadOnBlockImportEnabled;
}

public boolean isForkChoiceProposerBoostUniquenessEnabled() {
return forkChoiceProposerBoostUniquenessEnabled;
}

public Optional<UInt64> getForkEpoch(final SpecMilestone specMilestone) {
return switch (specMilestone) {
case ALTAIR -> altairForkEpoch;
@@ -248,6 +256,8 @@ public static class Builder {
private Spec spec;
private boolean forkChoiceUpdateHeadOnBlockImportEnabled =
DEFAULT_FORK_CHOICE_UPDATE_HEAD_ON_BLOCK_IMPORT_ENABLED;
private boolean forkChoiceProposerBoostUniquenessEnabled =
DEFAULT_FORK_CHOICE_PROPOSER_BOOST_UNIQUENESS_ENABLED;

public void spec(Spec spec) {
this.spec = spec;
@@ -310,6 +320,7 @@ public Eth2NetworkConfiguration build() {
eth1DepositContractDeployBlock,
trustedSetup,
forkChoiceUpdateHeadOnBlockImportEnabled,
forkChoiceProposerBoostUniquenessEnabled,
altairForkEpoch,
bellatrixForkEpoch,
capellaForkEpoch,
@@ -415,6 +426,12 @@ public Builder forkChoiceUpdateHeadOnBlockImportEnabled(
return this;
}

public Builder forkChoiceProposerBoostUniquenessEnabled(
final boolean forkChoiceProposerBoostUniquenessEnabled) {
this.forkChoiceProposerBoostUniquenessEnabled = forkChoiceProposerBoostUniquenessEnabled;
return this;
}

public Builder altairForkEpoch(final UInt64 altairForkEpoch) {
this.altairForkEpoch = Optional.of(altairForkEpoch);
return this;
Original file line number Diff line number Diff line change
@@ -50,7 +50,10 @@ public AttesterSlashingGenerator(final Spec spec, final List<BLSKeyPair> validat
public AttesterSlashing createAttesterSlashingForAttestation(
final Attestation goodAttestation, final SignedBlockAndState blockAndState) {
if (!goodAttestation.getData().getSlot().equals(blockAndState.getSlot())) {
throw new RuntimeException("Good attestation slot and input block slot should match");
throw new RuntimeException(
String.format(
"Good attestation slot %s and input block slot %s should match",
goodAttestation.getData().getSlot(), blockAndState.getSlot()));
}
AttestationUtil attestationUtil = spec.atSlot(blockAndState.getSlot()).getAttestationUtil();
IndexedAttestation indexedGoodAttestation =
Original file line number Diff line number Diff line change
@@ -353,7 +353,7 @@ public List<SignedBlockAndState> generateBlocksUpToSlot(final UInt64 slot) {
final List<SignedBlockAndState> generated = new ArrayList<>();

SignedBlockAndState latestBlock = getLatestBlockAndState();
while (latestBlock.getState().getSlot().compareTo(slot) < 0) {
while (latestBlock.getState().getSlot().isLessThan(slot)) {
latestBlock = generateNextBlock();
generated.add(latestBlock);
}
Original file line number Diff line number Diff line change
@@ -93,6 +93,7 @@ public class ForkChoice implements ForkChoiceUpdatedResultSubscriber {
private final ForkChoiceNotifier forkChoiceNotifier;
private final MergeTransitionBlockValidator transitionBlockValidator;
private final boolean forkChoiceUpdateHeadOnBlockImportEnabled;
private final boolean forkChoiceProposerBoostUniquenessEnabled;
private final AttestationStateSelector attestationStateSelector;
private final DeferredAttestations deferredAttestations = new DeferredAttestations();

@@ -111,6 +112,7 @@ public ForkChoice(
final TickProcessor tickProcessor,
final MergeTransitionBlockValidator transitionBlockValidator,
final boolean forkChoiceUpdateHeadOnBlockImportEnabled,
final boolean forkChoiceProposerBoostUniquenessEnabled,
final MetricsSystem metricsSystem) {
this.spec = spec;
this.forkChoiceExecutor = forkChoiceExecutor;
@@ -123,6 +125,7 @@ public ForkChoice(
new AttestationStateSelector(spec, recentChainData, metricsSystem);
this.tickProcessor = tickProcessor;
this.forkChoiceUpdateHeadOnBlockImportEnabled = forkChoiceUpdateHeadOnBlockImportEnabled;
this.forkChoiceProposerBoostUniquenessEnabled = forkChoiceProposerBoostUniquenessEnabled;
recentChainData.subscribeStoreInitialized(this::initializeProtoArrayForkChoice);
forkChoiceNotifier.subscribeToForkChoiceUpdatedResult(this);
}
@@ -150,6 +153,7 @@ public ForkChoice(
new TickProcessor(spec, recentChainData),
transitionBlockValidator,
true,
true,
metricsSystem);
}

@@ -488,23 +492,20 @@ private BlockImportResult importBlockAndState(
}

switch (blobSidecarsAndValidationResult.getValidationResult()) {
case VALID:
case NOT_REQUIRED:
LOG.debug(
"blobSidecars validation result: {}", blobSidecarsAndValidationResult::toLogString);

break;
case NOT_AVAILABLE:
case VALID, NOT_REQUIRED -> LOG.debug(
"blobSidecars validation result: {}", blobSidecarsAndValidationResult::toLogString);
case NOT_AVAILABLE -> {
LOG.warn(
"blobSidecars validation result: {}", blobSidecarsAndValidationResult::toLogString);
return BlockImportResult.failedDataAvailabilityCheckNotAvailable(
blobSidecarsAndValidationResult.getCause());

case INVALID:
}
case INVALID -> {
LOG.error(
"blobSidecars validation result: {}", blobSidecarsAndValidationResult::toLogString);
return BlockImportResult.failedDataAvailabilityCheckInvalid(
blobSidecarsAndValidationResult.getCause());
}
}

final ForkChoiceStrategy forkChoiceStrategy = getForkChoiceStrategy();
@@ -542,13 +543,8 @@ private BlockImportResult importBlockAndState(
blobSidecars,
earliestBlobSidecarsSlot);

if (spec.getCurrentSlot(transaction).equals(block.getSlot())) {
final UInt64 millisPerSlot = spec.getMillisPerSlot(block.getSlot());
final UInt64 timeIntoSlotMillis = getMillisIntoSlot(transaction, millisPerSlot);

if (isBeforeAttestingInterval(millisPerSlot, timeIntoSlotMillis)) {
transaction.setProposerBoostRoot(block.getRoot());
}
if (shouldApplyProposerBoost(block, transaction)) {
transaction.setProposerBoostRoot(block.getRoot());
}

blockImportPerformance.ifPresent(BlockImportPerformance::transactionReady);
@@ -582,6 +578,26 @@ private BlockImportResult importBlockAndState(
return result;
}

// from consensus-specs/fork-choice:
private boolean shouldApplyProposerBoost(
final SignedBeaconBlock block, final StoreTransaction transaction) {
// get_current_slot(store) == block.slot
if (!spec.getCurrentSlot(transaction).equals(block.getSlot())) {
return false;
}
// is_before_attesting_interval
final UInt64 millisPerSlot = spec.getMillisPerSlot(block.getSlot());
final UInt64 timeIntoSlotMillis = getMillisIntoSlot(transaction, millisPerSlot);
if (!isBeforeAttestingInterval(millisPerSlot, timeIntoSlotMillis)) {
return false;
}
// is_first_block
if (forkChoiceProposerBoostUniquenessEnabled) {
return transaction.getProposerBoostRoot().isEmpty();
}
return true;
}

/**
* In order to keep track of DataAvailability Window, we need to compute the earliest slot we can
* consider data available for the given block. It needs to take in account possible empty slots
Loading

0 comments on commit 9f169a8

Please sign in to comment.