per-validator payload builder configuration (#5062)

This commit is contained in:
tersec 2023-06-25 14:00:17 +02:00 committed by GitHub
parent 614202e30d
commit ba597ef0a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 103 additions and 27 deletions

View File

@ -115,14 +115,34 @@ template rng*(node: BeaconNode): ref HmacDrbgContext =
proc currentSlot*(node: BeaconNode): Slot =
node.beaconClock.now.slotOrZero
func getPayloadBuilderAddress*(config: BeaconNodeConf): Opt[string] =
if config.payloadBuilderEnable:
Opt.some config.payloadBuilderUrl
else:
Opt.none(string)
proc getPayloadBuilderClient*(
node: BeaconNode, validator_index: uint64): RestResult[RestClientRef] =
if node.config.payloadBuilderEnable:
# Logging done in caller
let res = RestClientRef.new(node.config.payloadBuilderUrl)
if res.isOk and res.get.isNil:
err "Got nil payload builder REST client reference"
else:
res
if not node.config.payloadBuilderEnable:
return err "Payload builder globally disabled"
let
defaultPayloadBuilderAddress = node.config.getPayloadBuilderAddress
pubkey = withState(node.dag.headState):
if validator_index >= forkyState.data.validators.lenu64:
return err "Validator index too high"
forkyState.data.validators.item(validator_index).pubkey
payloadBuilderAddress =
if node.keyManagerHost.isNil:
defaultPayloadBuilderAddress
else:
node.keyManagerHost[].getBuilderConfig(pubkey).valueOr:
defaultPayloadBuilderAddress
if payloadBuilderAddress.isNone:
return err "Payload builder disabled"
let res = RestClientRef.new(payloadBuilderAddress.get)
if res.isOk and res.get.isNil:
err "Got nil payload builder REST client reference"
else:
err "Payload builder globally disabled"
res

View File

@ -689,6 +689,7 @@ proc init*(T: type BeaconNode,
config.secretsDir,
config.defaultFeeRecipient,
config.suggestedGasLimit,
config.getPayloadBuilderAddress,
getValidatorAndIdx,
getBeaconTime,
getForkForEpoch,

View File

@ -336,6 +336,7 @@ proc asyncInit(vc: ValidatorClientRef): Future[ValidatorClientRef] {.async.} =
vc.config.secretsDir,
vc.config.defaultFeeRecipient,
vc.config.suggestedGasLimit,
Opt.none(string),
nil,
vc.beaconClock.getBeaconTimeFn,
getForkForEpoch,

View File

@ -8,8 +8,8 @@
{.push raises: [].}
import
std/[os, strutils, terminal, wordwrap, unicode],
chronicles, chronos, json_serialization, zxcvbn,
std/[os, unicode],
chronicles, chronos, json_serialization,
bearssl/rand,
serialization, blscurve, eth/common/eth_types, confutils,
nimbus_security_resources,
@ -21,6 +21,12 @@ import
".."/networking/network_metadata,
./validator_pool
from std/terminal import
ForegroundColor, Style, readPasswordFromStdin, getch, resetAttributes,
setForegroundColor, setStyle
from std/wordwrap import wrapWords
from zxcvbn import passwordEntropy
export
keystore, validator_pool, crypto, rand
@ -32,11 +38,11 @@ when defined(windows):
const
KeystoreFileName* = "keystore.json"
RemoteKeystoreFileName* = "remote_keystore.json"
NetKeystoreFileName* = "network_keystore.json"
FeeRecipientFilename* = "suggested_fee_recipient.hex"
GasLimitFilename* = "suggested_gas_limit.json"
KeyNameSize* = 98 # 0x + hexadecimal key representation 96 characters.
MaxKeystoreFileSize* = 65536
FeeRecipientFilename = "suggested_fee_recipient.hex"
GasLimitFilename = "suggested_gas_limit.json"
BuilderConfigPath = "payload_builder.json"
KeyNameSize = 98 # 0x + hexadecimal key representation 96 characters.
MaxKeystoreFileSize = 65536
type
WalletPathPair* = object
@ -47,9 +53,7 @@ type
walletPath*: WalletPathPair
seed*: KeySeed
KmResult*[T] = Result[T, cstring]
AnyKeystore* = RemoteKeystore | Keystore
KmResult[T] = Result[T, cstring]
RemoveValidatorStatus* {.pure.} = enum
deleted = "Deleted"
@ -59,11 +63,11 @@ type
existingArtifacts = "Keystore artifacts already exists"
failed = "Validator not added"
AddValidatorFailure* = object
AddValidatorFailure = object
status*: AddValidatorStatus
message*: string
ImportResult*[T] = Result[T, AddValidatorFailure]
ImportResult[T] = Result[T, AddValidatorFailure]
ValidatorPubKeyToDataFn* =
proc (pubkey: ValidatorPubKey): Opt[ValidatorAndIndex]
@ -82,6 +86,7 @@ type
secretsDir*: string
defaultFeeRecipient*: Opt[Eth1Address]
defaultGasLimit*: uint64
defaultBuilderAddress*: Opt[string]
getValidatorAndIdxFn*: ValidatorPubKeyToDataFn
getBeaconTimeFn*: GetBeaconTimeFn
getForkFn*: GetForkFn
@ -110,6 +115,7 @@ func init*(T: type KeymanagerHost,
secretsDir: string,
defaultFeeRecipient: Opt[Eth1Address],
defaultGasLimit: uint64,
defaultBuilderAddress: Opt[string],
getValidatorAndIdxFn: ValidatorPubKeyToDataFn,
getBeaconTimeFn: GetBeaconTimeFn,
getForkFn: GetForkFn,
@ -121,6 +127,7 @@ func init*(T: type KeymanagerHost,
secretsDir: secretsDir,
defaultFeeRecipient: defaultFeeRecipient,
defaultGasLimit: defaultGasLimit,
defaultBuilderAddress: defaultBuilderAddress,
getValidatorAndIdxFn: getValidatorAndIdxFn,
getBeaconTimeFn: getBeaconTimeFn,
getForkFn: getForkFn,
@ -754,14 +761,17 @@ func gasLimitPath(validatorsDir: string,
pubkey: ValidatorPubKey): string =
validatorsDir.validatorKeystoreDir(pubkey) / GasLimitFilename
func builderConfigPath(validatorsDir: string,
pubkey: ValidatorPubKey): string =
validatorsDir.validatorKeystoreDir(pubkey) / BuilderConfigPath
proc getSuggestedFeeRecipient*(
validatorsDir: string, pubkey: ValidatorPubKey,
defaultFeeRecipient: Eth1Address):
Result[Eth1Address, ValidatorConfigFileStatus] =
# In this particular case, an error might be by design. If the file exists,
# but doesn't load or parse that's a more urgent matter to fix. Many people
# people might prefer, however, not to override their default suggested fee
# recipients per validator, so don't warn very loudly, if at all.
# but doesn't load or parse that is more urgent. People might prefer not to
# override default suggested fee recipients per validator, so don't warn.
if not dirExists(validatorsDir.validatorKeystoreDir(pubkey)):
return err noSuchValidator
@ -788,9 +798,8 @@ proc getSuggestedGasLimit*(
pubkey: ValidatorPubKey,
defaultGasLimit: uint64): Result[uint64, ValidatorConfigFileStatus] =
# In this particular case, an error might be by design. If the file exists,
# but doesn't load or parse that's a more urgent matter to fix. Many people
# people might prefer, however, not to override their default suggested gas
# limit per validator, so don't warn very loudly, if at all.
# but doesn't load or parse that is more urgent. People might prefer not to
# override their default suggested gas limit per validator, so don't warn.
if not dirExists(validatorsDir.validatorKeystoreDir(pubkey)):
return err noSuchValidator
@ -802,7 +811,7 @@ proc getSuggestedGasLimit*(
readFile(gasLimitPath), leading = false, trailing = true))
except SerializationError as e:
warn "Invalid local gas limit file", gasLimitPath,
err= e.formatMsg(gasLimitPath)
err = e.formatMsg(gasLimitPath)
err malformedConfigFile
except CatchableError as exc:
warn "Failed to load gas limit file; falling back to default gas limit",
@ -810,6 +819,46 @@ proc getSuggestedGasLimit*(
err = exc.msg
err malformedConfigFile
type
BuilderConfig = object
payloadBuilderEnable: bool
payloadBuilderUrl: string
proc getBuilderConfig*(
validatorsDir: string, pubkey: ValidatorPubKey,
defaultBuilderAddress: Opt[string]):
Result[Opt[string], ValidatorConfigFileStatus] =
# In this particular case, an error might be by design. If the file exists,
# but doesn't load or parse that is more urgent. People might prefer not to
# override default builder configs per validator, so don't warn.
if not dirExists(validatorsDir.validatorKeystoreDir(pubkey)):
return err noSuchValidator
let builderConfigPath = validatorsDir.builderConfigPath(pubkey)
if not fileExists(builderConfigPath):
return ok defaultBuilderAddress
let builderConfig =
try:
Json.loadFile(builderConfigPath, BuilderConfig,
requireAllFields = true)
except IOError as err:
# Any exception must be in the presence of such a file, and therefore
# an actual error worth logging
error "Failed to read payload builder configuration", err = err.msg,
path = builderConfigPath
return err malformedConfigFile
except SerializationError as err:
error "Invalid payload builder configuration",
err = err.formatMsg(builderConfigPath)
return err malformedConfigFile
ok(
if builderConfig.payloadBuilderEnable:
Opt.some builderConfig.payloadBuilderUrl
else:
Opt.none string)
type
KeystoreGenerationErrorKind* = enum
FailedToCreateValidatorsDir
@ -1445,6 +1494,11 @@ proc getSuggestedGasLimit*(
pubkey: ValidatorPubKey): Result[uint64, ValidatorConfigFileStatus] =
host.validatorsDir.getSuggestedGasLimit(pubkey, host.defaultGasLimit)
proc getBuilderConfig*(
host: KeymanagerHost, pubkey: ValidatorPubKey):
Result[Opt[string], ValidatorConfigFileStatus] =
host.validatorsDir.getBuilderConfig(pubkey, host.defaultBuilderAddress)
proc addValidator*(
host: KeymanagerHost, keystore: KeystoreData,
withdrawalAddress: Opt[Eth1Address]) =