Skip to content

Commit

Permalink
big step
Browse files Browse the repository at this point in the history
  • Loading branch information
tbenr committed Jan 25, 2022
1 parent 99d45ab commit b7fdfa8
Show file tree
Hide file tree
Showing 16 changed files with 402 additions and 145 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@

import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.KeyDeserializer;
import tech.pegasys.teku.api.schema.BLSPubKey;
import org.apache.tuweni.bytes.Bytes48;

public class BLSPubKeyKeyDeserializer extends KeyDeserializer {
public class Bytes48KeyDeserializer extends KeyDeserializer {

@Override
public Object deserializeKey(String key, DeserializationContext ctxt) {
return BLSPubKey.fromHexString(key);
return Bytes48.fromHexString(key);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.Bytes48;
import org.apache.tuweni.units.bigints.UInt256;
import tech.pegasys.teku.api.response.v1.validator.GetNewBlockResponse;
import tech.pegasys.teku.api.response.v2.debug.GetStateResponseV2;
Expand All @@ -44,7 +45,8 @@ private void addTekuMappers() {
module.addDeserializer(BLSPubKey.class, new BLSPubKeyDeserializer());
module.addDeserializer(BLSSignature.class, new BLSSignatureDeserializer());
module.addSerializer(BLSSignature.class, new BLSSignatureSerializer());
module.addKeyDeserializer(BLSPubKey.class, new BLSPubKeyKeyDeserializer());

module.addKeyDeserializer(Bytes48.class, new Bytes48KeyDeserializer());

module.addDeserializer(Bytes32.class, new Bytes32Deserializer());
module.addDeserializer(Bytes4.class, new Bytes4Deserializer());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,22 @@ public class ValidatorProposerOptions {
private String proposerConfig = null;

@Option(
names = {"--Xvalidators-proposer-config-refresh-rate"},
paramLabel = "<INTEGER>",
names = {"--Xvalidators-proposer-config-refresh-enabled"},
paramLabel = "<BOOLEAN>",
description =
"Sets the frequency, in seconds, at which the proposer configuration is reloaded. "
+ "0 means never refresh.",
"Enable the proposer configuration reload on every proposer preparation (once per epoch)",
arity = "0..1",
fallbackValue = "true",
hidden = true)
private long proposerConfigRefreshRate =
ValidatorConfig.DEFAULT_VALIDATOR_PROPOSER_CONFIG_REFRESH_RATE.toSeconds();
private boolean proposerConfigRefreshEnabled =
ValidatorConfig.DEFAULT_VALIDATOR_PROPOSER_CONFIG_REFRESH_ENABLED;

public void configure(TekuConfiguration.Builder builder) {
builder.validator(
config ->
config
.proposerDefaultFeeRecipient(proposerDefaultFeeRecipient)
.proposerConfigSource(proposerConfig)
.proposerConfigSourceRefreshRate(proposerConfigRefreshRate));
.refreshProposerConfigFromSource(proposerConfigRefreshEnabled));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ public class ValidatorConfig {
public static final boolean DEFAULT_GENERATE_EARLY_ATTESTATIONS = true;
public static final boolean DEFAULT_SEND_ATTESTATIONS_AS_BATCH = true;
public static final Optional<Bytes32> DEFAULT_GRAFFITI = Optional.empty();
public static final Duration DEFAULT_VALIDATOR_PROPOSER_CONFIG_REFRESH_RATE =
Duration.ofSeconds(60);
public static final boolean DEFAULT_VALIDATOR_PROPOSER_CONFIG_REFRESH_ENABLED = false;

private final List<String> validatorKeys;
private final List<String> validatorExternalSignerPublicKeySources;
Expand All @@ -61,7 +60,7 @@ public class ValidatorConfig {
private final boolean generateEarlyAttestations;
private final Optional<Eth1Address> proposerDefaultFeeRecipient;
private final String proposerConfigSource;
private final long proposerConfigSourceRefreshRate;
private final boolean refreshProposerConfigFromSource;

private ValidatorConfig(
final List<String> validatorKeys,
Expand All @@ -82,7 +81,7 @@ private ValidatorConfig(
final boolean generateEarlyAttestations,
final Optional<Eth1Address> proposerDefaultFeeRecipient,
final String proposerConfigSource,
final long proposerConfigSourceRefreshRate) {
final boolean refreshProposerConfigFromSource) {
this.validatorKeys = validatorKeys;
this.validatorExternalSignerPublicKeySources = validatorExternalSignerPublicKeySources;
this.validatorExternalSignerUrl = validatorExternalSignerUrl;
Expand All @@ -104,7 +103,7 @@ private ValidatorConfig(
this.generateEarlyAttestations = generateEarlyAttestations;
this.proposerDefaultFeeRecipient = proposerDefaultFeeRecipient;
this.proposerConfigSource = proposerConfigSource;
this.proposerConfigSourceRefreshRate = proposerConfigSourceRefreshRate;
this.refreshProposerConfigFromSource = refreshProposerConfigFromSource;
}

public static Builder builder() {
Expand Down Expand Up @@ -173,6 +172,14 @@ public Optional<Eth1Address> getProposerDefaultFeeRecipient() {
return proposerDefaultFeeRecipient;
}

public String getProposerConfigSource() {
return proposerConfigSource;
}

public boolean getRefreshProposerConfigFromSource() {
return refreshProposerConfigFromSource;
}

private void validateProposerDefaultFeeRecipient() {
if (proposerDefaultFeeRecipient.isEmpty()
&& !(validatorKeys.isEmpty() && validatorExternalSignerPublicKeySources.isEmpty())) {
Expand Down Expand Up @@ -204,7 +211,7 @@ public static final class Builder {
private boolean generateEarlyAttestations = DEFAULT_GENERATE_EARLY_ATTESTATIONS;
private Optional<Eth1Address> proposerDefaultFeeRecipient = Optional.empty();
private String proposerConfigSource;
private long proposerConfigSourceRefreshRate;
private boolean refreshProposerConfigFromSource;

private Builder() {}

Expand Down Expand Up @@ -319,8 +326,8 @@ public Builder proposerConfigSource(final String proposerConfigSource) {
return this;
}

public Builder proposerConfigSourceRefreshRate(final long proposerConfigSourceRefreshRate) {
this.proposerConfigSourceRefreshRate = proposerConfigSourceRefreshRate;
public Builder refreshProposerConfigFromSource(final boolean refreshProposerConfigFromSource) {
this.refreshProposerConfigFromSource = refreshProposerConfigFromSource;
return this;
}

Expand Down Expand Up @@ -348,7 +355,7 @@ public ValidatorConfig build() {
generateEarlyAttestations,
proposerDefaultFeeRecipient,
proposerConfigSource,
proposerConfigSourceRefreshRate);
refreshProposerConfigFromSource);
}

private void validateExternalSignerUrlAndPublicKeys() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,63 +15,107 @@

import static tech.pegasys.teku.infrastructure.logging.ValidatorLogger.VALIDATOR_LOGGER;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tuweni.bytes.Bytes32;
import tech.pegasys.teku.bls.BLSPublicKey;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
import tech.pegasys.teku.infrastructure.exceptions.InvalidConfigurationException;
import tech.pegasys.teku.infrastructure.ssz.type.Bytes20;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.datastructures.operations.versions.bellatrix.BeaconPreparableProposer;
import tech.pegasys.teku.validator.api.ValidatorApiChannel;
import tech.pegasys.teku.validator.api.ValidatorTimingChannel;
import tech.pegasys.teku.validator.client.loader.OwnedValidators;
import tech.pegasys.teku.validator.client.ProposerConfig.Config;
import tech.pegasys.teku.validator.client.proposerconfig.ProposerConfigProvider;

public class BeaconProposerPreparer implements ValidatorTimingChannel {
private static final Logger LOG = LogManager.getLogger();

private final ValidatorApiChannel validatorApiChannel;
private final ValidatorIndexProvider validatorIndexProvider;
private final OwnedValidators validators;
private final ProposerConfigProvider proposerConfigProvider;
private final Spec spec;
private final Optional<? extends Bytes20> feeRecipient;
private final Optional<? extends Bytes20> defaultFeeRecipient;
private boolean firstCallDone = false;

public BeaconProposerPreparer(
ValidatorApiChannel validatorApiChannel,
ValidatorIndexProvider validatorIndexProvider,
Optional<? extends Bytes20> feeRecipient,
OwnedValidators validators,
ProposerConfigProvider proposerConfigProvider,
Optional<? extends Bytes20> defaultFeeRecipient,
Spec spec) {
this.validatorApiChannel = validatorApiChannel;
this.validatorIndexProvider = validatorIndexProvider;
this.validators = validators;
this.feeRecipient = feeRecipient;
this.proposerConfigProvider = proposerConfigProvider;
this.defaultFeeRecipient = defaultFeeRecipient;
this.spec = spec;
}

@Override
public void onSlot(UInt64 slot) {
if (slot.mod(spec.getSlotsPerEpoch(slot)).isZero() || !firstCallDone) {
firstCallDone = true;

SafeFuture<Optional<ProposerConfig>> proposerConfigFuture =
proposerConfigProvider.getProposerConfig();

validatorIndexProvider
.getValidatorIndices(validators.getPublicKeys())
.getValidatorIndexesByPublicKey()
.thenApply(
integers ->
integers.stream()
.map(
index ->
new BeaconPreparableProposer(
UInt64.valueOf(index), getFeeRecipient()))
.collect(Collectors.toList()))
blsPublicKeyIntegerMap ->
proposerConfigFuture
.thenApply(
proposerConfig ->
buildBeaconPreparableProposerList(
proposerConfig, blsPublicKeyIntegerMap))
.exceptionally(
throwable -> {
LOG.warn(
"An error occurred while obtaining proposer config", throwable);
return buildBeaconPreparableProposerList(
Optional.empty(), blsPublicKeyIntegerMap);
})
.join())
.thenAccept(validatorApiChannel::prepareBeaconProposer)
.finish(VALIDATOR_LOGGER::beaconProposerPreparationFailed);
}
}

private Bytes20 getFeeRecipient() {
return feeRecipient.orElseThrow(
() ->
new InvalidConfigurationException(
"Invalid configuration. --Xvalidators-proposer-default-fee-recipient must be specified when Bellatrix milestone is active"));
private List<BeaconPreparableProposer> buildBeaconPreparableProposerList(
Optional<ProposerConfig> maybeProposerConfig,
Map<BLSPublicKey, Integer> blsPublicKeyIntegerMap) {
return blsPublicKeyIntegerMap.entrySet().stream()
.map(
blsPublicKeyIntegerEntry ->
new BeaconPreparableProposer(
UInt64.valueOf(blsPublicKeyIntegerEntry.getValue()),
getFeeRecipient(maybeProposerConfig, blsPublicKeyIntegerEntry.getKey())))
.collect(Collectors.toList());
}

private Bytes20 getFeeRecipient(
Optional<ProposerConfig> maybeProposerConfig, BLSPublicKey blsPublicKey) {
return maybeProposerConfig
.flatMap(proposerConfig -> proposerConfig.getConfigForPubKey(blsPublicKey))
.map(Config::getFeeRecipient)
.orElseGet(() -> getDefaultFeeRecipient(maybeProposerConfig));
}

private Bytes20 getDefaultFeeRecipient(Optional<ProposerConfig> maybeProposerConfig) {
return maybeProposerConfig
.flatMap(proposerConfig -> proposerConfig.getDefaultConfig())
.map(Config::getFeeRecipient)
.or(() -> defaultFeeRecipient)
.orElseThrow(
() ->
new InvalidConfigurationException(
"Invalid configuration. --Xvalidators-proposer-default-fee-recipient must be specified when Bellatrix milestone is active"));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,37 @@

package tech.pegasys.teku.validator.client;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Map;
import java.util.Optional;
import tech.pegasys.teku.api.schema.BLSPubKey;
import org.apache.tuweni.bytes.Bytes48;
import tech.pegasys.teku.bls.BLSPublicKey;
import tech.pegasys.teku.infrastructure.ssz.type.Bytes20;

public class ProposerConfig {
@JsonProperty(value = "proposer_config", required = true)
private Map<BLSPubKey, Config> proposerConfig;
private Map<Bytes48, Config> proposerConfig;

@JsonProperty(value = "default_config", required = true)
private Config defaultConfig;

@JsonCreator
ProposerConfig(@JsonProperty(value = "proposer_config", required = true) final Map<Bytes48, Config> proposerConfig, @JsonProperty(value = "default_config", required = true) final Config defaultConfig) {
this.proposerConfig = proposerConfig;
this.defaultConfig = defaultConfig;
}

public Optional<Config> getConfigForPubKey(final String pubKey) {
return getConfigForPubKey(BLSPubKey.fromHexString(pubKey));
return getConfigForPubKey(Bytes48.fromHexString(pubKey));
}

public Optional<Config> getConfigForPubKey(final BLSPublicKey pubKey) {
return getConfigForPubKey(pubKey.toBytesCompressed());
}

public Optional<Config> getConfigForPubKey(final BLSPubKey pubKey) {
public Optional<Config> getConfigForPubKey(final Bytes48 pubKey) {
return Optional.ofNullable(proposerConfig.get(pubKey));
}

Expand All @@ -44,6 +56,11 @@ public static class Config {
@JsonProperty(value = "fee_recipient", required = true)
private Bytes20 feeRecipient;

@JsonCreator
Config(@JsonProperty(value = "fee_recipient", required = true) final Bytes20 feeRecipient) {
this.feeRecipient = feeRecipient;
}

public Bytes20 getFeeRecipient() {
return feeRecipient;
}
Expand Down

This file was deleted.

Loading

0 comments on commit b7fdfa8

Please sign in to comment.