Skip to content

Commit f2fdbe7

Browse files
authored
Add plumbing for PeerDAS supernodes (#5050, #5409, #5570, #5966) (#6216)
* Add plumbing for peerdas supernodes (#5050, #5409, #5570, #5966) - add cli option `--subscribe-to-all-data-columns` - add custody subnet count to ENR, only if PeerDAS is scheduled - subscribe to data column topics, only if PeerDAS is scheduled Co-authored-by: Jacob Kaufmann <[email protected]> * Merge branch 'unstable' into das-supernode * Update CLI docs. * Merge branch 'unstable' into das-supernode * Fix fork epoch comparison with `FAR_FUTURE_EPOCH`. * Merge branch 'unstable' into das-supernode * Hide `--subscribe-all-data-column-subnets` flag and update help. * Fix docs only * Merge branch 'unstable' into das-supernode
1 parent 781c5ec commit f2fdbe7

File tree

13 files changed

+223
-17
lines changed

13 files changed

+223
-17
lines changed

beacon_node/beacon_chain/src/builder.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ pub struct BeaconChainBuilder<T: BeaconChainTypes> {
104104
kzg: Option<Arc<Kzg>>,
105105
task_executor: Option<TaskExecutor>,
106106
validator_monitor_config: Option<ValidatorMonitorConfig>,
107+
import_all_data_columns: bool,
107108
}
108109

109110
impl<TSlotClock, TEth1Backend, E, THotStore, TColdStore>
@@ -145,6 +146,7 @@ where
145146
kzg: None,
146147
task_executor: None,
147148
validator_monitor_config: None,
149+
import_all_data_columns: false,
148150
}
149151
}
150152

@@ -615,6 +617,12 @@ where
615617
self
616618
}
617619

620+
/// Sets whether to require and import all data columns when importing block.
621+
pub fn import_all_data_columns(mut self, import_all_data_columns: bool) -> Self {
622+
self.import_all_data_columns = import_all_data_columns;
623+
self
624+
}
625+
618626
/// Sets the `BeaconChain` event handler backend.
619627
///
620628
/// For example, provide `ServerSentEventHandler` as a `handler`.
@@ -965,8 +973,15 @@ where
965973
validator_monitor: RwLock::new(validator_monitor),
966974
genesis_backfill_slot,
967975
data_availability_checker: Arc::new(
968-
DataAvailabilityChecker::new(slot_clock, self.kzg.clone(), store, &log, self.spec)
969-
.map_err(|e| format!("Error initializing DataAvailabiltyChecker: {:?}", e))?,
976+
DataAvailabilityChecker::new(
977+
slot_clock,
978+
self.kzg.clone(),
979+
store,
980+
self.import_all_data_columns,
981+
&log,
982+
self.spec,
983+
)
984+
.map_err(|e| format!("Error initializing DataAvailabilityChecker: {:?}", e))?,
970985
),
971986
kzg: self.kzg.clone(),
972987
};

beacon_node/beacon_chain/src/data_availability_checker.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,16 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
9595
slot_clock: T::SlotClock,
9696
kzg: Option<Arc<Kzg>>,
9797
store: BeaconStore<T>,
98+
import_all_data_columns: bool,
9899
log: &Logger,
99100
spec: ChainSpec,
100101
) -> Result<Self, AvailabilityCheckError> {
101-
// TODO(das): support supernode or custom custody requirement
102-
let custody_subnet_count = spec.custody_requirement as usize;
102+
let custody_subnet_count = if import_all_data_columns {
103+
spec.data_column_sidecar_subnet_count as usize
104+
} else {
105+
spec.custody_requirement as usize
106+
};
107+
103108
let custody_column_count =
104109
custody_subnet_count.saturating_mul(spec.data_columns_per_subnet());
105110

@@ -112,8 +117,8 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
112117
Ok(Self {
113118
availability_cache: Arc::new(overflow_cache),
114119
slot_clock,
115-
log: log.clone(),
116120
kzg,
121+
log: log.clone(),
117122
spec,
118123
})
119124
}

beacon_node/client/src/builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ where
207207
.beacon_graffiti(beacon_graffiti)
208208
.event_handler(event_handler)
209209
.execution_layer(execution_layer)
210+
.import_all_data_columns(config.network.subscribe_all_data_column_subnets)
210211
.validator_monitor_config(config.validator_monitor.clone());
211212

212213
let builder = if let Some(slasher) = self.slasher.clone() {

beacon_node/lighthouse_network/src/config.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub struct Config {
4242
pub network_dir: PathBuf,
4343

4444
/// IP addresses to listen on.
45-
listen_addresses: ListenAddress,
45+
pub(crate) listen_addresses: ListenAddress,
4646

4747
/// The address to broadcast to peers about which address we are listening on. None indicates
4848
/// that no discovery address has been set in the CLI args.
@@ -100,6 +100,9 @@ pub struct Config {
100100
/// Attempt to construct external port mappings with UPnP.
101101
pub upnp_enabled: bool,
102102

103+
/// Subscribe to all data column subnets for the duration of the runtime.
104+
pub subscribe_all_data_column_subnets: bool,
105+
103106
/// Subscribe to all subnets for the duration of the runtime.
104107
pub subscribe_all_subnets: bool,
105108

@@ -338,6 +341,7 @@ impl Default for Config {
338341
upnp_enabled: true,
339342
network_load: 4,
340343
private: false,
344+
subscribe_all_data_column_subnets: false,
341345
subscribe_all_subnets: false,
342346
import_all_attestations: false,
343347
shutdown_after_sync: false,

beacon_node/lighthouse_network/src/discovery/enr.rs

Lines changed: 107 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::fs::File;
1414
use std::io::prelude::*;
1515
use std::path::Path;
1616
use std::str::FromStr;
17-
use types::{EnrForkId, EthSpec};
17+
use types::{ChainSpec, EnrForkId, EthSpec};
1818

1919
use super::enr_ext::{EnrExt, QUIC6_ENR_KEY, QUIC_ENR_KEY};
2020

@@ -24,6 +24,8 @@ pub const ETH2_ENR_KEY: &str = "eth2";
2424
pub const ATTESTATION_BITFIELD_ENR_KEY: &str = "attnets";
2525
/// The ENR field specifying the sync committee subnet bitfield.
2626
pub const SYNC_COMMITTEE_BITFIELD_ENR_KEY: &str = "syncnets";
27+
/// The ENR field specifying the peerdas custody subnet count.
28+
pub const PEERDAS_CUSTODY_SUBNET_COUNT_ENR_KEY: &str = "csc";
2729

2830
/// Extension trait for ENR's within Eth2.
2931
pub trait Eth2Enr {
@@ -35,6 +37,9 @@ pub trait Eth2Enr {
3537
&self,
3638
) -> Result<EnrSyncCommitteeBitfield<E>, &'static str>;
3739

40+
/// The peerdas custody subnet count associated with the ENR.
41+
fn custody_subnet_count<E: EthSpec>(&self, spec: &ChainSpec) -> u64;
42+
3843
fn eth2(&self) -> Result<EnrForkId, &'static str>;
3944
}
4045

@@ -59,6 +64,16 @@ impl Eth2Enr for Enr {
5964
.map_err(|_| "Could not decode the ENR syncnets bitfield")
6065
}
6166

67+
/// if the custody value is non-existent in the ENR, then we assume the minimum custody value
68+
/// defined in the spec.
69+
fn custody_subnet_count<E: EthSpec>(&self, spec: &ChainSpec) -> u64 {
70+
self.get_decodable::<u64>(PEERDAS_CUSTODY_SUBNET_COUNT_ENR_KEY)
71+
.and_then(|r| r.ok())
72+
// If value supplied in ENR is invalid, fallback to `custody_requirement`
73+
.filter(|csc| csc <= &spec.data_column_sidecar_subnet_count)
74+
.unwrap_or(spec.custody_requirement)
75+
}
76+
6277
fn eth2(&self) -> Result<EnrForkId, &'static str> {
6378
let eth2_bytes = self.get(ETH2_ENR_KEY).ok_or("ENR has no eth2 field")?;
6479

@@ -126,12 +141,13 @@ pub fn build_or_load_enr<E: EthSpec>(
126141
config: &NetworkConfig,
127142
enr_fork_id: &EnrForkId,
128143
log: &slog::Logger,
144+
spec: &ChainSpec,
129145
) -> Result<Enr, String> {
130146
// Build the local ENR.
131147
// Note: Discovery should update the ENR record's IP to the external IP as seen by the
132148
// majority of our peers, if the CLI doesn't expressly forbid it.
133149
let enr_key = CombinedKey::from_libp2p(local_key)?;
134-
let mut local_enr = build_enr::<E>(&enr_key, config, enr_fork_id)?;
150+
let mut local_enr = build_enr::<E>(&enr_key, config, enr_fork_id, spec)?;
135151

136152
use_or_load_enr(&enr_key, &mut local_enr, config, log)?;
137153
Ok(local_enr)
@@ -142,6 +158,7 @@ pub fn build_enr<E: EthSpec>(
142158
enr_key: &CombinedKey,
143159
config: &NetworkConfig,
144160
enr_fork_id: &EnrForkId,
161+
spec: &ChainSpec,
145162
) -> Result<Enr, String> {
146163
let mut builder = discv5::enr::Enr::builder();
147164
let (maybe_ipv4_address, maybe_ipv6_address) = &config.enr_address;
@@ -221,6 +238,16 @@ pub fn build_enr<E: EthSpec>(
221238

222239
builder.add_value(SYNC_COMMITTEE_BITFIELD_ENR_KEY, &bitfield.as_ssz_bytes());
223240

241+
// only set `csc` if PeerDAS fork epoch has been scheduled
242+
if spec.is_peer_das_scheduled() {
243+
let custody_subnet_count = if config.subscribe_all_data_column_subnets {
244+
spec.data_column_sidecar_subnet_count
245+
} else {
246+
spec.custody_requirement
247+
};
248+
builder.add_value(PEERDAS_CUSTODY_SUBNET_COUNT_ENR_KEY, &custody_subnet_count);
249+
}
250+
224251
builder
225252
.build(enr_key)
226253
.map_err(|e| format!("Could not build Local ENR: {:?}", e))
@@ -244,10 +271,12 @@ fn compare_enr(local_enr: &Enr, disk_enr: &Enr) -> bool {
244271
// take preference over disk udp port if one is not specified
245272
&& (local_enr.udp4().is_none() || local_enr.udp4() == disk_enr.udp4())
246273
&& (local_enr.udp6().is_none() || local_enr.udp6() == disk_enr.udp6())
247-
// we need the ATTESTATION_BITFIELD_ENR_KEY and SYNC_COMMITTEE_BITFIELD_ENR_KEY key to match,
248-
// otherwise we use a new ENR. This will likely only be true for non-validating nodes
274+
// we need the ATTESTATION_BITFIELD_ENR_KEY and SYNC_COMMITTEE_BITFIELD_ENR_KEY and
275+
// PEERDAS_CUSTODY_SUBNET_COUNT_ENR_KEY key to match, otherwise we use a new ENR. This will
276+
// likely only be true for non-validating nodes.
249277
&& local_enr.get(ATTESTATION_BITFIELD_ENR_KEY) == disk_enr.get(ATTESTATION_BITFIELD_ENR_KEY)
250278
&& local_enr.get(SYNC_COMMITTEE_BITFIELD_ENR_KEY) == disk_enr.get(SYNC_COMMITTEE_BITFIELD_ENR_KEY)
279+
&& local_enr.get(PEERDAS_CUSTODY_SUBNET_COUNT_ENR_KEY) == disk_enr.get(PEERDAS_CUSTODY_SUBNET_COUNT_ENR_KEY)
251280
}
252281

253282
/// Loads enr from the given directory
@@ -280,3 +309,77 @@ pub fn save_enr_to_disk(dir: &Path, enr: &Enr, log: &slog::Logger) {
280309
}
281310
}
282311
}
312+
313+
#[cfg(test)]
314+
mod test {
315+
use super::*;
316+
use crate::config::Config as NetworkConfig;
317+
use types::{Epoch, MainnetEthSpec};
318+
319+
type E = MainnetEthSpec;
320+
321+
fn make_eip7594_spec() -> ChainSpec {
322+
let mut spec = E::default_spec();
323+
spec.eip7594_fork_epoch = Some(Epoch::new(10));
324+
spec
325+
}
326+
327+
#[test]
328+
fn custody_subnet_count_default() {
329+
let config = NetworkConfig {
330+
subscribe_all_data_column_subnets: false,
331+
..NetworkConfig::default()
332+
};
333+
let spec = make_eip7594_spec();
334+
335+
let enr = build_enr_with_config(config, &spec).0;
336+
337+
assert_eq!(
338+
enr.custody_subnet_count::<E>(&spec),
339+
spec.custody_requirement,
340+
);
341+
}
342+
343+
#[test]
344+
fn custody_subnet_count_all() {
345+
let config = NetworkConfig {
346+
subscribe_all_data_column_subnets: true,
347+
..NetworkConfig::default()
348+
};
349+
let spec = make_eip7594_spec();
350+
let enr = build_enr_with_config(config, &spec).0;
351+
352+
assert_eq!(
353+
enr.custody_subnet_count::<E>(&spec),
354+
spec.data_column_sidecar_subnet_count,
355+
);
356+
}
357+
358+
#[test]
359+
fn custody_subnet_count_fallback_default() {
360+
let config = NetworkConfig::default();
361+
let spec = make_eip7594_spec();
362+
let (mut enr, enr_key) = build_enr_with_config(config, &spec);
363+
let invalid_subnet_count = 99u64;
364+
365+
enr.insert(
366+
PEERDAS_CUSTODY_SUBNET_COUNT_ENR_KEY,
367+
&invalid_subnet_count,
368+
&enr_key,
369+
)
370+
.unwrap();
371+
372+
assert_eq!(
373+
enr.custody_subnet_count::<E>(&spec),
374+
spec.custody_requirement,
375+
);
376+
}
377+
378+
fn build_enr_with_config(config: NetworkConfig, spec: &ChainSpec) -> (Enr, CombinedKey) {
379+
let keypair = libp2p::identity::secp256k1::Keypair::generate();
380+
let enr_key = CombinedKey::from_secp256k1(&keypair);
381+
let enr_fork_id = EnrForkId::default();
382+
let enr = build_enr::<E>(&enr_key, &config, &enr_fork_id, spec).unwrap();
383+
(enr, enr_key)
384+
}
385+
}

beacon_node/lighthouse_network/src/discovery/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1220,7 +1220,7 @@ mod tests {
12201220
let mut config = NetworkConfig::default();
12211221
config.set_listening_addr(crate::ListenAddress::unused_v4_ports());
12221222
let enr_key: CombinedKey = CombinedKey::from_secp256k1(&keypair);
1223-
let enr: Enr = build_enr::<E>(&enr_key, &config, &EnrForkId::default()).unwrap();
1223+
let enr: Enr = build_enr::<E>(&enr_key, &config, &EnrForkId::default(), &spec).unwrap();
12241224
let log = build_log(slog::Level::Debug, false);
12251225
let globals = NetworkGlobals::new(
12261226
enr,

beacon_node/lighthouse_network/src/service/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ impl<E: EthSpec> Network<E> {
162162
&config,
163163
&ctx.enr_fork_id,
164164
&log,
165+
ctx.chain_spec,
165166
)?;
166167
// Construct the metadata
167168
let meta_data = utils::load_or_build_metadata(&config.network_dir, &log);

0 commit comments

Comments
 (0)