Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MEV boost] improve blinded block validator options and flow handling #5341

Merged
merged 2 commits into from
Apr 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,20 @@ public void shouldSignBlock() {
assertThat(result).isCompletedWithValue(expectedSignature);
}

@Test
public void shouldSignBlindedBlock() {
final BeaconBlock block = dataStructureUtil.randomBlindedBeaconBlock(10);
final BLSSignature expectedSignature =
BLSSignature.fromBytesCompressed(
Bytes.fromBase64String(
"pbSSuf7h70JkzI/U157flTWPZDuaBXgRLj1HLMoCwjA4Xd0hMdGewn7G2HLZiQcNC9G6FSd1+0BT5PwknYez4ya6TccwpaGnsvWYLPf3SNIX5Ug7Yi1CF1fvEr3x9sZ0"));

final SafeFuture<BLSSignature> result = signer.signBlock(block, fork);
asyncRunner.executeQueuedActions();

assertThat(result).isCompletedWithValue(expectedSignature);
}

@Test
public void shouldCreateRandaoReveal() {
final BLSSignature expectedSignature =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,10 @@ public BeaconBlock randomBeaconBlock(UInt64 slotNum) {
body);
}

public BeaconBlock randomBlindedBeaconBlock(long slotNum) {
return randomBlindedBeaconBlock(UInt64.valueOf(slotNum));
}

public BeaconBlock randomBlindedBeaconBlock(UInt64 slotNum) {
final UInt64 proposerIndex = randomUInt64();
Bytes32 previousRoot = randomBytes32();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@

package tech.pegasys.teku.cli.options;

import static tech.pegasys.teku.validator.api.ValidatorConfig.DEFAULT_VALIDATOR_BLINDED_BLOCKS_ENABLED;

import java.nio.file.Path;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes32;
Expand Down Expand Up @@ -102,16 +100,6 @@ public class ValidatorOptions {
arity = "0..1")
private boolean generateEarlyAttestations = ValidatorConfig.DEFAULT_GENERATE_EARLY_ATTESTATIONS;

@Option(
names = {"--Xvalidators-blinded-blocks-api-enabled"},
paramLabel = "<BOOLEAN>",
showDefaultValue = Visibility.ALWAYS,
description = "Use blinded block api calls",
fallbackValue = "true",
hidden = true,
arity = "0..1")
private boolean blindedBlocksApiEnabled = DEFAULT_VALIDATOR_BLINDED_BLOCKS_ENABLED;

public void configure(TekuConfiguration.Builder builder) {
if (validatorPerformanceTrackingEnabled != null) {
if (validatorPerformanceTrackingEnabled) {
Expand All @@ -125,7 +113,6 @@ public void configure(TekuConfiguration.Builder builder) {
config ->
config
.validatorKeystoreLockingEnabled(validatorKeystoreLockingEnabled)
.blindedBeaconBlocksApiEnabled(blindedBlocksApiEnabled)
.validatorPerformanceTrackingMode(validatorPerformanceTrackingMode)
.validatorExternalSignerSlashingProtectionEnabled(
validatorExternalSignerSlashingProtectionEnabled)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

package tech.pegasys.teku.cli.options;

import static tech.pegasys.teku.validator.api.ValidatorConfig.DEFAULT_VALIDATOR_BLINDED_BLOCKS_ENABLED;

import picocli.CommandLine.Help.Visibility;
import picocli.CommandLine.Option;
import tech.pegasys.teku.config.TekuConfiguration;
Expand Down Expand Up @@ -56,13 +58,24 @@ public class ValidatorProposerOptions {
private boolean proposerMevBoostEnabled =
ValidatorConfig.DEFAULT_VALIDATOR_PROPOSER_MEV_BOOST_ENABLED;

@Option(
names = {"--Xvalidators-proposer-blinded-blocks-enabled"},
paramLabel = "<BOOLEAN>",
showDefaultValue = Visibility.ALWAYS,
description = "Use blinded blocks when in block production duties",
fallbackValue = "true",
hidden = true,
arity = "0..1")
private boolean blindedBlocksEnabled = DEFAULT_VALIDATOR_BLINDED_BLOCKS_ENABLED;
tbenr marked this conversation as resolved.
Show resolved Hide resolved

public void configure(TekuConfiguration.Builder builder) {
builder.validator(
config ->
config
.proposerDefaultFeeRecipient(proposerDefaultFeeRecipient)
.proposerConfigSource(proposerConfig)
.refreshProposerConfigFromSource(proposerConfigRefreshEnabled)
.proposerMevBoostEnabled(proposerMevBoostEnabled));
.proposerMevBoostEnabled(proposerMevBoostEnabled)
.blindedBeaconBlocksEnabled(blindedBlocksEnabled));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@

package tech.pegasys.teku.cli.subcommand;

import static tech.pegasys.teku.validator.api.ValidatorConfig.DEFAULT_VALIDATOR_BLINDED_BLOCKS_ENABLED;

import java.net.URI;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -91,7 +89,6 @@ static OkHttpValidatorRestApiClient createApiClient(final URI baseEndpoint) {
// Strip any authentication info from the URL to ensure it doesn't get logged.
apiEndpoint = apiEndpoint.newBuilder().username("").password("").build();
final OkHttpClient okHttpClient = httpClientBuilder.build();
return new OkHttpValidatorRestApiClient(
apiEndpoint, okHttpClient, DEFAULT_VALIDATOR_BLINDED_BLOCKS_ENABLED);
return new OkHttpValidatorRestApiClient(apiEndpoint, okHttpClient);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -119,17 +119,33 @@ public void shouldReportAddressIfFeeRecipientSpecified() {

@Test
public void shouldEnableBlindedBeaconBlocks() {
final String[] args = {"--Xvalidators-blinded-blocks-api-enabled", "true"};
final String[] args = {"--Xvalidators-proposer-blinded-blocks-enabled", "true"};
final TekuConfiguration config = getTekuConfigurationFromArguments(args);
assertThat(config.validatorClient().getValidatorConfig().isBlindedBeaconBlocksApiEnabled())
assertThat(config.validatorClient().getValidatorConfig().isBlindedBeaconBlocksEnabled())
.isTrue();
}

@Test
public void shouldNotUseBlindedBeaconBlocksByDefault() {
final String[] args = {};
final TekuConfiguration config = getTekuConfigurationFromArguments(args);
assertThat(config.validatorClient().getValidatorConfig().isBlindedBeaconBlocksApiEnabled())
assertThat(config.validatorClient().getValidatorConfig().isBlindedBeaconBlocksEnabled())
.isFalse();
}

@Test
public void shouldEnableMevBoostWithBlindedBlocks() {
final String[] args = {"--Xvalidators-proposer-mev-boost-enabled", "true"};
final TekuConfiguration config = getTekuConfigurationFromArguments(args);
assertThat(config.validatorClient().getValidatorConfig().isProposerMevBoostEnabled()).isTrue();
assertThat(config.validatorClient().getValidatorConfig().isBlindedBeaconBlocksEnabled())
.isTrue();
}

@Test
public void shouldNotUseMevBoostByDefault() {
final String[] args = {};
final TekuConfiguration config = getTekuConfigurationFromArguments(args);
assertThat(config.validatorClient().getValidatorConfig().isProposerMevBoostEnabled()).isFalse();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@
import java.util.List;
import java.util.Optional;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tuweni.bytes.Bytes32;
import tech.pegasys.teku.infrastructure.exceptions.InvalidConfigurationException;
import tech.pegasys.teku.spec.datastructures.eth1.Eth1Address;

public class ValidatorConfig {
private static final Logger LOG = LogManager.getLogger();

private static final int DEFAULT_REST_API_PORT = 5051;
public static final String DEFAULT_BEACON_NODE_API_ENDPOINT =
Expand Down Expand Up @@ -60,7 +63,7 @@ public class ValidatorConfig {
private final Optional<Eth1Address> proposerDefaultFeeRecipient;
private final Optional<String> proposerConfigSource;
private final boolean refreshProposerConfigFromSource;
private final boolean blindedBeaconBlocksApiEnabled;
private final boolean blindedBeaconBlocksEnabled;
private final boolean proposerMevBoostEnabled;

private ValidatorConfig(
Expand All @@ -83,7 +86,7 @@ private ValidatorConfig(
final Optional<String> proposerConfigSource,
final boolean refreshProposerConfigFromSource,
final boolean proposerMevBoostEnabled,
final boolean blindedBeaconBlocksApiEnabled) {
final boolean blindedBeaconBlocksEnabled) {
this.validatorKeys = validatorKeys;
this.validatorExternalSignerPublicKeySources = validatorExternalSignerPublicKeySources;
this.validatorExternalSignerUrl = validatorExternalSignerUrl;
Expand All @@ -105,7 +108,7 @@ private ValidatorConfig(
this.proposerDefaultFeeRecipient = proposerDefaultFeeRecipient;
this.proposerConfigSource = proposerConfigSource;
this.refreshProposerConfigFromSource = refreshProposerConfigFromSource;
this.blindedBeaconBlocksApiEnabled = blindedBeaconBlocksApiEnabled;
this.blindedBeaconBlocksEnabled = blindedBeaconBlocksEnabled;
this.proposerMevBoostEnabled = proposerMevBoostEnabled;
}

Expand Down Expand Up @@ -180,8 +183,8 @@ public boolean getRefreshProposerConfigFromSource() {
return refreshProposerConfigFromSource;
}

public boolean isBlindedBeaconBlocksApiEnabled() {
return blindedBeaconBlocksApiEnabled;
public boolean isBlindedBeaconBlocksEnabled() {
return blindedBeaconBlocksEnabled;
}

public boolean isProposerMevBoostEnabled() {
Expand Down Expand Up @@ -222,7 +225,7 @@ public static final class Builder {
private boolean refreshProposerConfigFromSource =
DEFAULT_VALIDATOR_PROPOSER_CONFIG_REFRESH_ENABLED;
private boolean proposerMevBoostEnabled = DEFAULT_VALIDATOR_PROPOSER_MEV_BOOST_ENABLED;
private boolean blindedBlocksApiEnabled = DEFAULT_VALIDATOR_BLINDED_BLOCKS_ENABLED;
private boolean blindedBlocksEnabled = DEFAULT_VALIDATOR_BLINDED_BLOCKS_ENABLED;

private Builder() {}

Expand Down Expand Up @@ -353,8 +356,8 @@ public Builder proposerMevBoostEnabled(final boolean proposerMevBoostEnabled) {
return this;
}

public Builder blindedBeaconBlocksApiEnabled(final boolean blindedBeaconBlockEnabled) {
this.blindedBlocksApiEnabled = blindedBeaconBlockEnabled;
public Builder blindedBeaconBlocksEnabled(final boolean blindedBeaconBlockEnabled) {
this.blindedBlocksEnabled = blindedBeaconBlockEnabled;
return this;
}

Expand All @@ -363,6 +366,7 @@ public ValidatorConfig build() {
validateExternalSignerKeystoreAndPasswordFileConfig();
validateExternalSignerTruststoreAndPasswordFileConfig();
validateExternalSignerURLScheme();
validateMevBoostAndBlindedBlocks();
return new ValidatorConfig(
validatorKeys,
validatorExternalSignerPublicKeySources,
Expand All @@ -383,7 +387,7 @@ public ValidatorConfig build() {
proposerConfigSource,
refreshProposerConfigFromSource,
proposerMevBoostEnabled,
blindedBlocksApiEnabled);
blindedBlocksEnabled);
}

private void validateExternalSignerUrlAndPublicKeys() {
Expand Down Expand Up @@ -432,6 +436,14 @@ private void validateExternalSignerURLScheme() {
}
}

private void validateMevBoostAndBlindedBlocks() {
if (proposerMevBoostEnabled && !blindedBlocksEnabled) {
LOG.info(
"'--Xvalidators-proposer-mev-boost-enabled' requires '--Xvalidators-proposer-blinded-blocks-enabled', enabling it");
blindedBlocksEnabled = true;
}
}

private static boolean isURLSchemeHttps(final URL url) {
final String protocol = url.getProtocol();
return protocol != null && protocol.equalsIgnoreCase("https");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,6 @@ public static ValidatorClientService create(
final AsyncRunner asyncRunner = services.createAsyncRunner("validator");
final boolean generateEarlyAttestations =
config.getValidatorConfig().generateEarlyAttestations();
final boolean blindedBlocksEnabled =
config.getValidatorConfig().isBlindedBeaconBlocksApiEnabled();
final BeaconNodeApi beaconNodeApi =
config
.getValidatorConfig()
Expand All @@ -112,8 +110,7 @@ public static ValidatorClientService create(
asyncRunner,
endpoint,
config.getSpec(),
generateEarlyAttestations,
blindedBlocksEnabled))
generateEarlyAttestations))
.orElseGet(
() ->
InProcessBeaconNodeApi.create(
Expand Down Expand Up @@ -194,7 +191,11 @@ private void initializeValidators(
this.validatorIndexProvider =
new ValidatorIndexProvider(validators, validatorApiChannel, asyncRunner);
final BlockDutyFactory blockDutyFactory =
new BlockDutyFactory(forkProvider, validatorApiChannel, spec);
new BlockDutyFactory(
forkProvider,
validatorApiChannel,
config.getValidatorConfig().isBlindedBeaconBlocksEnabled(),
spec);
final AttestationDutyFactory attestationDutyFactory =
new AttestationDutyFactory(spec, forkProvider, validatorApiChannel);
final BeaconCommitteeSubscriptions beaconCommitteeSubscriptions =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,23 @@ public class BlockDutyFactory implements DutyFactory<BlockProductionDuty, Duty>
private final ForkProvider forkProvider;
private final ValidatorApiChannel validatorApiChannel;
private final Spec spec;
private final boolean useBlindedBlock;

public BlockDutyFactory(
final ForkProvider forkProvider,
final ValidatorApiChannel validatorApiChannel,
final boolean useBlindedBlock,
final Spec spec) {
this.forkProvider = forkProvider;

this.useBlindedBlock = useBlindedBlock;
this.validatorApiChannel = validatorApiChannel;
this.spec = spec;
}

@Override
public BlockProductionDuty createProductionDuty(final UInt64 slot, final Validator validator) {
return new BlockProductionDuty(validator, slot, forkProvider, validatorApiChannel, spec);
return new BlockProductionDuty(
validator, slot, forkProvider, validatorApiChannel, useBlindedBlock, spec);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,21 @@ public class BlockProductionDuty implements Duty {
private final UInt64 slot;
private final ForkProvider forkProvider;
private final ValidatorApiChannel validatorApiChannel;
private final boolean useBlindedBlock;
private final Spec spec;

public BlockProductionDuty(
final Validator validator,
final UInt64 slot,
final ForkProvider forkProvider,
final ValidatorApiChannel validatorApiChannel,
final boolean useBlindedBlock,
final Spec spec) {
this.validator = validator;
this.slot = slot;
this.forkProvider = forkProvider;
this.validatorApiChannel = validatorApiChannel;
this.useBlindedBlock = useBlindedBlock;
this.spec = spec;
}

Expand Down Expand Up @@ -82,7 +85,7 @@ private SafeFuture<DutyResult> sendBlock(final SignedBeaconBlock signedBlock) {

public SafeFuture<Optional<BeaconBlock>> createUnsignedBlock(final BLSSignature randaoReveal) {
return validatorApiChannel.createUnsignedBlock(
slot, randaoReveal, validator.getGraffiti(), false);
slot, randaoReveal, validator.getGraffiti(), useBlindedBlock);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This definitely makes more sense - nice clean up.

}

public SafeFuture<BLSSignature> createRandaoReveal(final ForkInfo forkInfo) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import tech.pegasys.teku.bls.BLSSignature;
import tech.pegasys.teku.core.signatures.Signer;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
Expand Down Expand Up @@ -62,22 +64,34 @@ class BlockProductionDutyTest {
private final ForkInfo fork = dataStructureUtil.randomForkInfo();
private final ValidatorLogger validatorLogger = mock(ValidatorLogger.class);

private final BlockProductionDuty duty =
new BlockProductionDuty(validator, SLOT, forkProvider, validatorApiChannel, spec);
private BlockProductionDuty duty;

@BeforeEach
public void setUp() {
duty = new BlockProductionDuty(validator, SLOT, forkProvider, validatorApiChannel, false, spec);
when(forkProvider.getForkInfo(any())).thenReturn(completedFuture(fork));
}

@Test
public void shouldCreateAndPublishBlock() {
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void shouldCreateAndPublishBlock(final boolean isBlindedBlocksEnabled) {
duty =
new BlockProductionDuty(
validator, SLOT, forkProvider, validatorApiChannel, isBlindedBlocksEnabled, spec);
final BLSSignature randaoReveal = dataStructureUtil.randomSignature();
final BLSSignature blockSignature = dataStructureUtil.randomSignature();
final BeaconBlock unsignedBlock = dataStructureUtil.randomBeaconBlock(SLOT.longValue());
final BeaconBlock unsignedBlock;

if (isBlindedBlocksEnabled) {
unsignedBlock = dataStructureUtil.randomBlindedBeaconBlock(SLOT);
} else {
unsignedBlock = dataStructureUtil.randomBeaconBlock(SLOT);
}

when(signer.createRandaoReveal(spec.computeEpochAtSlot(SLOT), fork))
.thenReturn(completedFuture(randaoReveal));
when(validatorApiChannel.createUnsignedBlock(SLOT, randaoReveal, Optional.of(graffiti), false))
when(validatorApiChannel.createUnsignedBlock(
SLOT, randaoReveal, Optional.of(graffiti), isBlindedBlocksEnabled))
.thenReturn(completedFuture(Optional.of(unsignedBlock)));
when(signer.signBlock(unsignedBlock, fork)).thenReturn(completedFuture(blockSignature));
final SignedBeaconBlock signedBlock =
Expand Down
Loading