mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-02-17 00:47:03 +00:00
per-validator payload builder configuration (#5062)
This commit is contained in:
parent
614202e30d
commit
ba597ef0a2
@ -115,14 +115,34 @@ template rng*(node: BeaconNode): ref HmacDrbgContext =
|
|||||||
proc currentSlot*(node: BeaconNode): Slot =
|
proc currentSlot*(node: BeaconNode): Slot =
|
||||||
node.beaconClock.now.slotOrZero
|
node.beaconClock.now.slotOrZero
|
||||||
|
|
||||||
|
func getPayloadBuilderAddress*(config: BeaconNodeConf): Opt[string] =
|
||||||
|
if config.payloadBuilderEnable:
|
||||||
|
Opt.some config.payloadBuilderUrl
|
||||||
|
else:
|
||||||
|
Opt.none(string)
|
||||||
|
|
||||||
proc getPayloadBuilderClient*(
|
proc getPayloadBuilderClient*(
|
||||||
node: BeaconNode, validator_index: uint64): RestResult[RestClientRef] =
|
node: BeaconNode, validator_index: uint64): RestResult[RestClientRef] =
|
||||||
if node.config.payloadBuilderEnable:
|
if not node.config.payloadBuilderEnable:
|
||||||
# Logging done in caller
|
return err "Payload builder globally disabled"
|
||||||
let res = RestClientRef.new(node.config.payloadBuilderUrl)
|
|
||||||
if res.isOk and res.get.isNil:
|
let
|
||||||
err "Got nil payload builder REST client reference"
|
defaultPayloadBuilderAddress = node.config.getPayloadBuilderAddress
|
||||||
else:
|
pubkey = withState(node.dag.headState):
|
||||||
res
|
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:
|
else:
|
||||||
err "Payload builder globally disabled"
|
res
|
||||||
|
@ -689,6 +689,7 @@ proc init*(T: type BeaconNode,
|
|||||||
config.secretsDir,
|
config.secretsDir,
|
||||||
config.defaultFeeRecipient,
|
config.defaultFeeRecipient,
|
||||||
config.suggestedGasLimit,
|
config.suggestedGasLimit,
|
||||||
|
config.getPayloadBuilderAddress,
|
||||||
getValidatorAndIdx,
|
getValidatorAndIdx,
|
||||||
getBeaconTime,
|
getBeaconTime,
|
||||||
getForkForEpoch,
|
getForkForEpoch,
|
||||||
|
@ -336,6 +336,7 @@ proc asyncInit(vc: ValidatorClientRef): Future[ValidatorClientRef] {.async.} =
|
|||||||
vc.config.secretsDir,
|
vc.config.secretsDir,
|
||||||
vc.config.defaultFeeRecipient,
|
vc.config.defaultFeeRecipient,
|
||||||
vc.config.suggestedGasLimit,
|
vc.config.suggestedGasLimit,
|
||||||
|
Opt.none(string),
|
||||||
nil,
|
nil,
|
||||||
vc.beaconClock.getBeaconTimeFn,
|
vc.beaconClock.getBeaconTimeFn,
|
||||||
getForkForEpoch,
|
getForkForEpoch,
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[os, strutils, terminal, wordwrap, unicode],
|
std/[os, unicode],
|
||||||
chronicles, chronos, json_serialization, zxcvbn,
|
chronicles, chronos, json_serialization,
|
||||||
bearssl/rand,
|
bearssl/rand,
|
||||||
serialization, blscurve, eth/common/eth_types, confutils,
|
serialization, blscurve, eth/common/eth_types, confutils,
|
||||||
nimbus_security_resources,
|
nimbus_security_resources,
|
||||||
@ -21,6 +21,12 @@ import
|
|||||||
".."/networking/network_metadata,
|
".."/networking/network_metadata,
|
||||||
./validator_pool
|
./validator_pool
|
||||||
|
|
||||||
|
from std/terminal import
|
||||||
|
ForegroundColor, Style, readPasswordFromStdin, getch, resetAttributes,
|
||||||
|
setForegroundColor, setStyle
|
||||||
|
from std/wordwrap import wrapWords
|
||||||
|
from zxcvbn import passwordEntropy
|
||||||
|
|
||||||
export
|
export
|
||||||
keystore, validator_pool, crypto, rand
|
keystore, validator_pool, crypto, rand
|
||||||
|
|
||||||
@ -32,11 +38,11 @@ when defined(windows):
|
|||||||
const
|
const
|
||||||
KeystoreFileName* = "keystore.json"
|
KeystoreFileName* = "keystore.json"
|
||||||
RemoteKeystoreFileName* = "remote_keystore.json"
|
RemoteKeystoreFileName* = "remote_keystore.json"
|
||||||
NetKeystoreFileName* = "network_keystore.json"
|
FeeRecipientFilename = "suggested_fee_recipient.hex"
|
||||||
FeeRecipientFilename* = "suggested_fee_recipient.hex"
|
GasLimitFilename = "suggested_gas_limit.json"
|
||||||
GasLimitFilename* = "suggested_gas_limit.json"
|
BuilderConfigPath = "payload_builder.json"
|
||||||
KeyNameSize* = 98 # 0x + hexadecimal key representation 96 characters.
|
KeyNameSize = 98 # 0x + hexadecimal key representation 96 characters.
|
||||||
MaxKeystoreFileSize* = 65536
|
MaxKeystoreFileSize = 65536
|
||||||
|
|
||||||
type
|
type
|
||||||
WalletPathPair* = object
|
WalletPathPair* = object
|
||||||
@ -47,9 +53,7 @@ type
|
|||||||
walletPath*: WalletPathPair
|
walletPath*: WalletPathPair
|
||||||
seed*: KeySeed
|
seed*: KeySeed
|
||||||
|
|
||||||
KmResult*[T] = Result[T, cstring]
|
KmResult[T] = Result[T, cstring]
|
||||||
|
|
||||||
AnyKeystore* = RemoteKeystore | Keystore
|
|
||||||
|
|
||||||
RemoveValidatorStatus* {.pure.} = enum
|
RemoveValidatorStatus* {.pure.} = enum
|
||||||
deleted = "Deleted"
|
deleted = "Deleted"
|
||||||
@ -59,11 +63,11 @@ type
|
|||||||
existingArtifacts = "Keystore artifacts already exists"
|
existingArtifacts = "Keystore artifacts already exists"
|
||||||
failed = "Validator not added"
|
failed = "Validator not added"
|
||||||
|
|
||||||
AddValidatorFailure* = object
|
AddValidatorFailure = object
|
||||||
status*: AddValidatorStatus
|
status*: AddValidatorStatus
|
||||||
message*: string
|
message*: string
|
||||||
|
|
||||||
ImportResult*[T] = Result[T, AddValidatorFailure]
|
ImportResult[T] = Result[T, AddValidatorFailure]
|
||||||
|
|
||||||
ValidatorPubKeyToDataFn* =
|
ValidatorPubKeyToDataFn* =
|
||||||
proc (pubkey: ValidatorPubKey): Opt[ValidatorAndIndex]
|
proc (pubkey: ValidatorPubKey): Opt[ValidatorAndIndex]
|
||||||
@ -82,6 +86,7 @@ type
|
|||||||
secretsDir*: string
|
secretsDir*: string
|
||||||
defaultFeeRecipient*: Opt[Eth1Address]
|
defaultFeeRecipient*: Opt[Eth1Address]
|
||||||
defaultGasLimit*: uint64
|
defaultGasLimit*: uint64
|
||||||
|
defaultBuilderAddress*: Opt[string]
|
||||||
getValidatorAndIdxFn*: ValidatorPubKeyToDataFn
|
getValidatorAndIdxFn*: ValidatorPubKeyToDataFn
|
||||||
getBeaconTimeFn*: GetBeaconTimeFn
|
getBeaconTimeFn*: GetBeaconTimeFn
|
||||||
getForkFn*: GetForkFn
|
getForkFn*: GetForkFn
|
||||||
@ -110,6 +115,7 @@ func init*(T: type KeymanagerHost,
|
|||||||
secretsDir: string,
|
secretsDir: string,
|
||||||
defaultFeeRecipient: Opt[Eth1Address],
|
defaultFeeRecipient: Opt[Eth1Address],
|
||||||
defaultGasLimit: uint64,
|
defaultGasLimit: uint64,
|
||||||
|
defaultBuilderAddress: Opt[string],
|
||||||
getValidatorAndIdxFn: ValidatorPubKeyToDataFn,
|
getValidatorAndIdxFn: ValidatorPubKeyToDataFn,
|
||||||
getBeaconTimeFn: GetBeaconTimeFn,
|
getBeaconTimeFn: GetBeaconTimeFn,
|
||||||
getForkFn: GetForkFn,
|
getForkFn: GetForkFn,
|
||||||
@ -121,6 +127,7 @@ func init*(T: type KeymanagerHost,
|
|||||||
secretsDir: secretsDir,
|
secretsDir: secretsDir,
|
||||||
defaultFeeRecipient: defaultFeeRecipient,
|
defaultFeeRecipient: defaultFeeRecipient,
|
||||||
defaultGasLimit: defaultGasLimit,
|
defaultGasLimit: defaultGasLimit,
|
||||||
|
defaultBuilderAddress: defaultBuilderAddress,
|
||||||
getValidatorAndIdxFn: getValidatorAndIdxFn,
|
getValidatorAndIdxFn: getValidatorAndIdxFn,
|
||||||
getBeaconTimeFn: getBeaconTimeFn,
|
getBeaconTimeFn: getBeaconTimeFn,
|
||||||
getForkFn: getForkFn,
|
getForkFn: getForkFn,
|
||||||
@ -754,14 +761,17 @@ func gasLimitPath(validatorsDir: string,
|
|||||||
pubkey: ValidatorPubKey): string =
|
pubkey: ValidatorPubKey): string =
|
||||||
validatorsDir.validatorKeystoreDir(pubkey) / GasLimitFilename
|
validatorsDir.validatorKeystoreDir(pubkey) / GasLimitFilename
|
||||||
|
|
||||||
|
func builderConfigPath(validatorsDir: string,
|
||||||
|
pubkey: ValidatorPubKey): string =
|
||||||
|
validatorsDir.validatorKeystoreDir(pubkey) / BuilderConfigPath
|
||||||
|
|
||||||
proc getSuggestedFeeRecipient*(
|
proc getSuggestedFeeRecipient*(
|
||||||
validatorsDir: string, pubkey: ValidatorPubKey,
|
validatorsDir: string, pubkey: ValidatorPubKey,
|
||||||
defaultFeeRecipient: Eth1Address):
|
defaultFeeRecipient: Eth1Address):
|
||||||
Result[Eth1Address, ValidatorConfigFileStatus] =
|
Result[Eth1Address, ValidatorConfigFileStatus] =
|
||||||
# In this particular case, an error might be by design. If the file exists,
|
# 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
|
# but doesn't load or parse that is more urgent. People might prefer not to
|
||||||
# people might prefer, however, not to override their default suggested fee
|
# override default suggested fee recipients per validator, so don't warn.
|
||||||
# recipients per validator, so don't warn very loudly, if at all.
|
|
||||||
if not dirExists(validatorsDir.validatorKeystoreDir(pubkey)):
|
if not dirExists(validatorsDir.validatorKeystoreDir(pubkey)):
|
||||||
return err noSuchValidator
|
return err noSuchValidator
|
||||||
|
|
||||||
@ -788,9 +798,8 @@ proc getSuggestedGasLimit*(
|
|||||||
pubkey: ValidatorPubKey,
|
pubkey: ValidatorPubKey,
|
||||||
defaultGasLimit: uint64): Result[uint64, ValidatorConfigFileStatus] =
|
defaultGasLimit: uint64): Result[uint64, ValidatorConfigFileStatus] =
|
||||||
# In this particular case, an error might be by design. If the file exists,
|
# 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
|
# but doesn't load or parse that is more urgent. People might prefer not to
|
||||||
# people might prefer, however, not to override their default suggested gas
|
# override their default suggested gas limit per validator, so don't warn.
|
||||||
# limit per validator, so don't warn very loudly, if at all.
|
|
||||||
if not dirExists(validatorsDir.validatorKeystoreDir(pubkey)):
|
if not dirExists(validatorsDir.validatorKeystoreDir(pubkey)):
|
||||||
return err noSuchValidator
|
return err noSuchValidator
|
||||||
|
|
||||||
@ -802,7 +811,7 @@ proc getSuggestedGasLimit*(
|
|||||||
readFile(gasLimitPath), leading = false, trailing = true))
|
readFile(gasLimitPath), leading = false, trailing = true))
|
||||||
except SerializationError as e:
|
except SerializationError as e:
|
||||||
warn "Invalid local gas limit file", gasLimitPath,
|
warn "Invalid local gas limit file", gasLimitPath,
|
||||||
err= e.formatMsg(gasLimitPath)
|
err = e.formatMsg(gasLimitPath)
|
||||||
err malformedConfigFile
|
err malformedConfigFile
|
||||||
except CatchableError as exc:
|
except CatchableError as exc:
|
||||||
warn "Failed to load gas limit file; falling back to default gas limit",
|
warn "Failed to load gas limit file; falling back to default gas limit",
|
||||||
@ -810,6 +819,46 @@ proc getSuggestedGasLimit*(
|
|||||||
err = exc.msg
|
err = exc.msg
|
||||||
err malformedConfigFile
|
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
|
type
|
||||||
KeystoreGenerationErrorKind* = enum
|
KeystoreGenerationErrorKind* = enum
|
||||||
FailedToCreateValidatorsDir
|
FailedToCreateValidatorsDir
|
||||||
@ -1445,6 +1494,11 @@ proc getSuggestedGasLimit*(
|
|||||||
pubkey: ValidatorPubKey): Result[uint64, ValidatorConfigFileStatus] =
|
pubkey: ValidatorPubKey): Result[uint64, ValidatorConfigFileStatus] =
|
||||||
host.validatorsDir.getSuggestedGasLimit(pubkey, host.defaultGasLimit)
|
host.validatorsDir.getSuggestedGasLimit(pubkey, host.defaultGasLimit)
|
||||||
|
|
||||||
|
proc getBuilderConfig*(
|
||||||
|
host: KeymanagerHost, pubkey: ValidatorPubKey):
|
||||||
|
Result[Opt[string], ValidatorConfigFileStatus] =
|
||||||
|
host.validatorsDir.getBuilderConfig(pubkey, host.defaultBuilderAddress)
|
||||||
|
|
||||||
proc addValidator*(
|
proc addValidator*(
|
||||||
host: KeymanagerHost, keystore: KeystoreData,
|
host: KeymanagerHost, keystore: KeystoreData,
|
||||||
withdrawalAddress: Opt[Eth1Address]) =
|
withdrawalAddress: Opt[Eth1Address]) =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user