@@ -14,7 +14,7 @@ use std::fs::File;
14
14
use std:: io:: prelude:: * ;
15
15
use std:: path:: Path ;
16
16
use std:: str:: FromStr ;
17
- use types:: { EnrForkId , EthSpec } ;
17
+ use types:: { ChainSpec , EnrForkId , EthSpec } ;
18
18
19
19
use super :: enr_ext:: { EnrExt , QUIC6_ENR_KEY , QUIC_ENR_KEY } ;
20
20
@@ -24,6 +24,8 @@ pub const ETH2_ENR_KEY: &str = "eth2";
24
24
pub const ATTESTATION_BITFIELD_ENR_KEY : & str = "attnets" ;
25
25
/// The ENR field specifying the sync committee subnet bitfield.
26
26
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" ;
27
29
28
30
/// Extension trait for ENR's within Eth2.
29
31
pub trait Eth2Enr {
@@ -35,6 +37,9 @@ pub trait Eth2Enr {
35
37
& self ,
36
38
) -> Result < EnrSyncCommitteeBitfield < E > , & ' static str > ;
37
39
40
+ /// The peerdas custody subnet count associated with the ENR.
41
+ fn custody_subnet_count < E : EthSpec > ( & self , spec : & ChainSpec ) -> u64 ;
42
+
38
43
fn eth2 ( & self ) -> Result < EnrForkId , & ' static str > ;
39
44
}
40
45
@@ -59,6 +64,16 @@ impl Eth2Enr for Enr {
59
64
. map_err ( |_| "Could not decode the ENR syncnets bitfield" )
60
65
}
61
66
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
+
62
77
fn eth2 ( & self ) -> Result < EnrForkId , & ' static str > {
63
78
let eth2_bytes = self . get ( ETH2_ENR_KEY ) . ok_or ( "ENR has no eth2 field" ) ?;
64
79
@@ -126,12 +141,13 @@ pub fn build_or_load_enr<E: EthSpec>(
126
141
config : & NetworkConfig ,
127
142
enr_fork_id : & EnrForkId ,
128
143
log : & slog:: Logger ,
144
+ spec : & ChainSpec ,
129
145
) -> Result < Enr , String > {
130
146
// Build the local ENR.
131
147
// Note: Discovery should update the ENR record's IP to the external IP as seen by the
132
148
// majority of our peers, if the CLI doesn't expressly forbid it.
133
149
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 ) ?;
135
151
136
152
use_or_load_enr ( & enr_key, & mut local_enr, config, log) ?;
137
153
Ok ( local_enr)
@@ -142,6 +158,7 @@ pub fn build_enr<E: EthSpec>(
142
158
enr_key : & CombinedKey ,
143
159
config : & NetworkConfig ,
144
160
enr_fork_id : & EnrForkId ,
161
+ spec : & ChainSpec ,
145
162
) -> Result < Enr , String > {
146
163
let mut builder = discv5:: enr:: Enr :: builder ( ) ;
147
164
let ( maybe_ipv4_address, maybe_ipv6_address) = & config. enr_address ;
@@ -221,6 +238,16 @@ pub fn build_enr<E: EthSpec>(
221
238
222
239
builder. add_value ( SYNC_COMMITTEE_BITFIELD_ENR_KEY , & bitfield. as_ssz_bytes ( ) ) ;
223
240
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
+
224
251
builder
225
252
. build ( enr_key)
226
253
. map_err ( |e| format ! ( "Could not build Local ENR: {:?}" , e) )
@@ -244,10 +271,12 @@ fn compare_enr(local_enr: &Enr, disk_enr: &Enr) -> bool {
244
271
// take preference over disk udp port if one is not specified
245
272
&& ( local_enr. udp4 ( ) . is_none ( ) || local_enr. udp4 ( ) == disk_enr. udp4 ( ) )
246
273
&& ( 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.
249
277
&& local_enr. get ( ATTESTATION_BITFIELD_ENR_KEY ) == disk_enr. get ( ATTESTATION_BITFIELD_ENR_KEY )
250
278
&& 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 )
251
280
}
252
281
253
282
/// Loads enr from the given directory
@@ -280,3 +309,77 @@ pub fn save_enr_to_disk(dir: &Path, enr: &Enr, log: &slog::Logger) {
280
309
}
281
310
}
282
311
}
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
+ }
0 commit comments