Register validator api (#3194)

## Issue Addressed

Lays the groundwork for builder API changes by implementing the beacon-API's new `register_validator` endpoint

## Proposed Changes

- Add a routine in the VC that runs on startup (re-try until success), once per epoch or whenever `suggested_fee_recipient` is updated, signing `ValidatorRegistrationData` and sending it to the BN.
  -  TODO: `gas_limit` config options https://github.com/ethereum/builder-specs/issues/17
-  BN only sends VC registration data to builders on demand, but VC registration data *does update* the BN's prepare proposer cache and send an updated fcU to  a local EE. This is necessary for fee recipient consistency between the blinded and full block flow in the event of fallback.  Having the BN only send registration data to builders on demand gives feedback directly to the VC about relay status. Also, since the BN has no ability to sign these messages anyways (so couldn't refresh them if it wanted), and validator registration is independent of the BN head, I think this approach makes sense. 
- Adds upcoming consensus spec changes for this PR https://github.com/ethereum/consensus-specs/pull/2884
  -  I initially applied the bit mask based on a configured application domain.. but I ended up just hard coding it here instead because that's how it's spec'd in the builder repo. 
  -  Should application mask appear in the api?



Co-authored-by: realbigsean <sean@sigmaprime.io>
This commit is contained in:
realbigsean
2022-06-30 00:49:21 +00:00
parent 5de00b7ee8
commit f6ec44f0dd
18 changed files with 603 additions and 27 deletions

View File

@@ -0,0 +1,16 @@
/// This value is an application index of 0 with the bitmask applied (so it's equivalent to the bit mask).
/// Little endian hex: 0x00000001, Binary: 1000000000000000000000000
pub const APPLICATION_DOMAIN_BUILDER: u32 = 16777216;
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ApplicationDomain {
Builder,
}
impl ApplicationDomain {
pub fn get_domain_constant(&self) -> u32 {
match self {
ApplicationDomain::Builder => APPLICATION_DOMAIN_BUILDER,
}
}
}

View File

@@ -1,3 +1,4 @@
use crate::application_domain::{ApplicationDomain, APPLICATION_DOMAIN_BUILDER};
use crate::*;
use eth2_serde_utils::quoted_u64::MaybeQuoted;
use int_to_bytes::int_to_bytes4;
@@ -20,6 +21,7 @@ pub enum Domain {
SyncCommittee,
ContributionAndProof,
SyncCommitteeSelectionProof,
ApplicationMask(ApplicationDomain),
}
/// Lighthouse's internal configuration struct.
@@ -159,6 +161,11 @@ pub struct ChainSpec {
pub attestation_subnet_count: u64,
pub random_subnets_per_validator: u64,
pub epochs_per_random_subnet_subscription: u64,
/*
* Application params
*/
pub(crate) domain_application_mask: u32,
}
impl ChainSpec {
@@ -326,6 +333,7 @@ impl ChainSpec {
Domain::SyncCommittee => self.domain_sync_committee,
Domain::ContributionAndProof => self.domain_contribution_and_proof,
Domain::SyncCommitteeSelectionProof => self.domain_sync_committee_selection_proof,
Domain::ApplicationMask(application_domain) => application_domain.get_domain_constant(),
}
}
@@ -353,6 +361,17 @@ impl ChainSpec {
self.compute_domain(Domain::Deposit, self.genesis_fork_version, Hash256::zero())
}
// This should be updated to include the current fork and the genesis validators root, but discussion is ongoing:
//
// https://github.com/ethereum/builder-specs/issues/14
pub fn get_builder_domain(&self) -> Hash256 {
self.compute_domain(
Domain::ApplicationMask(ApplicationDomain::Builder),
self.genesis_fork_version,
Hash256::zero(),
)
}
/// Return the 32-byte fork data root for the `current_version` and `genesis_validators_root`.
///
/// This is used primarily in signature domains to avoid collisions across forks/chains.
@@ -565,6 +584,11 @@ impl ChainSpec {
maximum_gossip_clock_disparity_millis: 500,
target_aggregators_per_committee: 16,
epochs_per_random_subnet_subscription: 256,
/*
* Application specific
*/
domain_application_mask: APPLICATION_DOMAIN_BUILDER,
}
}
@@ -763,6 +787,11 @@ impl ChainSpec {
maximum_gossip_clock_disparity_millis: 500,
target_aggregators_per_committee: 16,
epochs_per_random_subnet_subscription: 256,
/*
* Application specific
*/
domain_application_mask: APPLICATION_DOMAIN_BUILDER,
}
}
}
@@ -1119,6 +1148,27 @@ mod tests {
&spec,
);
test_domain(Domain::SyncCommittee, spec.domain_sync_committee, &spec);
// The builder domain index is zero
let builder_domain_pre_mask = [0; 4];
test_domain(
Domain::ApplicationMask(ApplicationDomain::Builder),
apply_bit_mask(builder_domain_pre_mask, &spec),
&spec,
);
}
fn apply_bit_mask(domain_bytes: [u8; 4], spec: &ChainSpec) -> u32 {
let mut domain = [0; 4];
let mask_bytes = int_to_bytes4(spec.domain_application_mask);
// Apply application bit mask
for (i, (domain_byte, mask_byte)) in domain_bytes.iter().zip(mask_bytes.iter()).enumerate()
{
domain[i] = domain_byte | mask_byte;
}
u32::from_le_bytes(domain)
}
// Test that `fork_name_at_epoch` and `fork_epoch` are consistent.

View File

@@ -69,6 +69,10 @@ impl ConfigAndPreset {
"domain_aggregate_and_proof",
u32_hex(spec.domain_aggregate_and_proof),
),
(
"domain_application_mask",
u32_hex(spec.domain_application_mask),
),
(
"target_aggregators_per_committee",
spec.target_aggregators_per_committee.to_string(),

View File

@@ -18,6 +18,7 @@ extern crate lazy_static;
pub mod test_utils;
pub mod aggregate_and_proof;
pub mod application_domain;
pub mod attestation;
pub mod attestation_data;
pub mod attestation_duty;
@@ -82,6 +83,7 @@ pub mod sync_committee_message;
pub mod sync_selection_proof;
pub mod sync_subnet_id;
mod tree_hash_impls;
pub mod validator_registration_data;
pub mod slot_data;
#[cfg(feature = "sqlite")]
@@ -157,6 +159,7 @@ pub use crate::sync_duty::SyncDuty;
pub use crate::sync_selection_proof::SyncSelectionProof;
pub use crate::sync_subnet_id::SyncSubnetId;
pub use crate::validator::Validator;
pub use crate::validator_registration_data::*;
pub use crate::validator_subscription::ValidatorSubscription;
pub use crate::voluntary_exit::VoluntaryExit;

View File

@@ -0,0 +1,23 @@
use crate::*;
use serde::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use tree_hash_derive::TreeHash;
/// Validator registration, for use in interacting with servers implementing the builder API.
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
pub struct SignedValidatorRegistrationData {
pub message: ValidatorRegistrationData,
pub signature: Signature,
}
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone, Encode, Decode, TreeHash)]
pub struct ValidatorRegistrationData {
pub fee_recipient: Address,
#[serde(with = "eth2_serde_utils::quoted_u64")]
pub gas_limit: u64,
#[serde(with = "eth2_serde_utils::quoted_u64")]
pub timestamp: u64,
pub pubkey: PublicKeyBytes,
}
impl SignedRoot for ValidatorRegistrationData {}