1
+ use crate :: blob_verification:: GossipVerifiedBlob ;
1
2
use crate :: block_verification_types:: { AsBlock , RpcBlock } ;
3
+ use crate :: data_column_verification:: CustodyDataColumn ;
2
4
use crate :: kzg_utils:: blobs_to_data_column_sidecars;
3
5
use crate :: observed_operations:: ObservationOutcome ;
4
6
pub use crate :: persisted_beacon_chain:: PersistedBeaconChain ;
5
- use crate :: BeaconBlockResponseWrapper ;
6
7
pub use crate :: {
7
8
beacon_chain:: { BEACON_CHAIN_DB_KEY , ETH1_CACHE_DB_KEY , FORK_CHOICE_DB_KEY , OP_POOL_DB_KEY } ,
8
9
migrate:: MigratorConfig ,
@@ -16,6 +17,7 @@ use crate::{
16
17
BeaconChain , BeaconChainTypes , BlockError , ChainConfig , ServerSentEventHandler ,
17
18
StateSkipConfig ,
18
19
} ;
20
+ use crate :: { get_block_root, BeaconBlockResponseWrapper } ;
19
21
use bls:: get_withdrawal_credentials;
20
22
use eth2:: types:: SignedBlockContentsTuple ;
21
23
use execution_layer:: test_utils:: generate_genesis_header;
@@ -105,7 +107,7 @@ static KZG_NO_PRECOMP: LazyLock<Arc<Kzg>> = LazyLock::new(|| {
105
107
} ) ;
106
108
107
109
pub fn get_kzg ( spec : & ChainSpec ) -> Arc < Kzg > {
108
- if spec. eip7594_fork_epoch . is_some ( ) {
110
+ if spec. fulu_fork_epoch . is_some ( ) {
109
111
KZG_PEERDAS . clone ( )
110
112
} else if spec. deneb_fork_epoch . is_some ( ) {
111
113
KZG . clone ( )
@@ -762,15 +764,13 @@ where
762
764
pub fn get_head_block ( & self ) -> RpcBlock < E > {
763
765
let block = self . chain . head_beacon_block ( ) ;
764
766
let block_root = block. canonical_root ( ) ;
765
- let blobs = self . chain . get_blobs ( & block_root) . unwrap ( ) . blobs ( ) ;
766
- RpcBlock :: new ( Some ( block_root) , block, blobs) . unwrap ( )
767
+ self . build_rpc_block_from_store_blobs ( Some ( block_root) , block)
767
768
}
768
769
769
770
pub fn get_full_block ( & self , block_root : & Hash256 ) -> RpcBlock < E > {
770
771
let block = self . chain . get_blinded_block ( block_root) . unwrap ( ) . unwrap ( ) ;
771
772
let full_block = self . chain . store . make_full_block ( block_root, block) . unwrap ( ) ;
772
- let blobs = self . chain . get_blobs ( block_root) . unwrap ( ) . blobs ( ) ;
773
- RpcBlock :: new ( Some ( * block_root) , Arc :: new ( full_block) , blobs) . unwrap ( )
773
+ self . build_rpc_block_from_store_blobs ( Some ( * block_root) , Arc :: new ( full_block) )
774
774
}
775
775
776
776
pub fn get_all_validators ( & self ) -> Vec < usize > {
@@ -2271,22 +2271,19 @@ where
2271
2271
self . set_current_slot ( slot) ;
2272
2272
let ( block, blob_items) = block_contents;
2273
2273
2274
- let sidecars = blob_items
2275
- . map ( |( proofs, blobs) | BlobSidecar :: build_sidecars ( blobs, & block, proofs, & self . spec ) )
2276
- . transpose ( )
2277
- . unwrap ( ) ;
2274
+ let rpc_block = self . build_rpc_block_from_blobs ( block_root, block, blob_items) ?;
2278
2275
let block_hash: SignedBeaconBlockHash = self
2279
2276
. chain
2280
2277
. process_block (
2281
2278
block_root,
2282
- RpcBlock :: new ( Some ( block_root ) , block , sidecars ) . unwrap ( ) ,
2279
+ rpc_block ,
2283
2280
NotifyExecutionLayer :: Yes ,
2284
2281
BlockImportSource :: RangeSync ,
2285
2282
|| Ok ( ( ) ) ,
2286
2283
)
2287
2284
. await ?
2288
2285
. try_into ( )
2289
- . unwrap ( ) ;
2286
+ . expect ( "block blobs are available" ) ;
2290
2287
self . chain . recompute_head_at_current_slot ( ) . await ;
2291
2288
Ok ( block_hash)
2292
2289
}
@@ -2297,16 +2294,13 @@ where
2297
2294
) -> Result < SignedBeaconBlockHash , BlockError > {
2298
2295
let ( block, blob_items) = block_contents;
2299
2296
2300
- let sidecars = blob_items
2301
- . map ( |( proofs, blobs) | BlobSidecar :: build_sidecars ( blobs, & block, proofs, & self . spec ) )
2302
- . transpose ( )
2303
- . unwrap ( ) ;
2304
2297
let block_root = block. canonical_root ( ) ;
2298
+ let rpc_block = self . build_rpc_block_from_blobs ( block_root, block, blob_items) ?;
2305
2299
let block_hash: SignedBeaconBlockHash = self
2306
2300
. chain
2307
2301
. process_block (
2308
2302
block_root,
2309
- RpcBlock :: new ( Some ( block_root ) , block , sidecars ) . unwrap ( ) ,
2303
+ rpc_block ,
2310
2304
NotifyExecutionLayer :: Yes ,
2311
2305
BlockImportSource :: RangeSync ,
2312
2306
|| Ok ( ( ) ) ,
@@ -2318,6 +2312,82 @@ where
2318
2312
Ok ( block_hash)
2319
2313
}
2320
2314
2315
+ /// Builds an `Rpc` block from a `SignedBeaconBlock` and blobs or data columns retrieved from
2316
+ /// the database.
2317
+ pub fn build_rpc_block_from_store_blobs (
2318
+ & self ,
2319
+ block_root : Option < Hash256 > ,
2320
+ block : Arc < SignedBeaconBlock < E > > ,
2321
+ ) -> RpcBlock < E > {
2322
+ let block_root = block_root. unwrap_or_else ( || get_block_root ( & block) ) ;
2323
+ let has_blobs = block
2324
+ . message ( )
2325
+ . body ( )
2326
+ . blob_kzg_commitments ( )
2327
+ . is_ok_and ( |c| !c. is_empty ( ) ) ;
2328
+ if !has_blobs {
2329
+ return RpcBlock :: new_without_blobs ( Some ( block_root) , block) ;
2330
+ }
2331
+
2332
+ // Blobs are stored as data columns from Fulu (PeerDAS)
2333
+ if self . spec . is_peer_das_enabled_for_epoch ( block. epoch ( ) ) {
2334
+ let columns = self . chain . get_data_columns ( & block_root) . unwrap ( ) . unwrap ( ) ;
2335
+ let custody_columns = columns
2336
+ . into_iter ( )
2337
+ . map ( CustodyDataColumn :: from_asserted_custody)
2338
+ . collect :: < Vec < _ > > ( ) ;
2339
+ RpcBlock :: new_with_custody_columns ( Some ( block_root) , block, custody_columns, & self . spec )
2340
+ . unwrap ( )
2341
+ } else {
2342
+ let blobs = self . chain . get_blobs ( & block_root) . unwrap ( ) . blobs ( ) ;
2343
+ RpcBlock :: new ( Some ( block_root) , block, blobs) . unwrap ( )
2344
+ }
2345
+ }
2346
+
2347
+ /// Builds an `RpcBlock` from a `SignedBeaconBlock` and `BlobsList`.
2348
+ fn build_rpc_block_from_blobs (
2349
+ & self ,
2350
+ block_root : Hash256 ,
2351
+ block : Arc < SignedBeaconBlock < E , FullPayload < E > > > ,
2352
+ blob_items : Option < ( KzgProofs < E > , BlobsList < E > ) > ,
2353
+ ) -> Result < RpcBlock < E > , BlockError > {
2354
+ Ok ( if self . spec . is_peer_das_enabled_for_epoch ( block. epoch ( ) ) {
2355
+ let sampling_column_count = self
2356
+ . chain
2357
+ . data_availability_checker
2358
+ . get_sampling_column_count ( ) ;
2359
+
2360
+ let columns = blob_items
2361
+ . map ( |( _proofs, blobs) | {
2362
+ blobs_to_data_column_sidecars (
2363
+ & blobs. iter ( ) . collect :: < Vec < _ > > ( ) ,
2364
+ & block,
2365
+ & self . chain . kzg ,
2366
+ & self . spec ,
2367
+ )
2368
+ . map ( |column_sidecars| {
2369
+ column_sidecars
2370
+ . into_iter ( )
2371
+ . take ( sampling_column_count)
2372
+ . map ( CustodyDataColumn :: from_asserted_custody)
2373
+ . collect :: < Vec < _ > > ( )
2374
+ } )
2375
+ } )
2376
+ . transpose ( )
2377
+ . expect ( "should convert blobs to columns" )
2378
+ . unwrap_or_default ( ) ;
2379
+ RpcBlock :: new_with_custody_columns ( Some ( block_root) , block, columns, & self . spec ) ?
2380
+ } else {
2381
+ let blobs = blob_items
2382
+ . map ( |( proofs, blobs) | {
2383
+ BlobSidecar :: build_sidecars ( blobs, & block, proofs, & self . spec )
2384
+ } )
2385
+ . transpose ( )
2386
+ . unwrap ( ) ;
2387
+ RpcBlock :: new ( Some ( block_root) , block, blobs) ?
2388
+ } )
2389
+ }
2390
+
2321
2391
pub fn process_attestations ( & self , attestations : HarnessAttestations < E > ) {
2322
2392
let num_validators = self . validator_keypairs . len ( ) ;
2323
2393
let mut unaggregated = Vec :: with_capacity ( num_validators) ;
@@ -2991,6 +3061,60 @@ where
2991
3061
2992
3062
Ok ( ( ) )
2993
3063
}
3064
+
3065
+ /// Simulate some of the blobs / data columns being seen on gossip.
3066
+ /// Converts the blobs to data columns if the slot is Fulu or later.
3067
+ pub async fn process_gossip_blobs_or_columns < ' a > (
3068
+ & self ,
3069
+ block : & SignedBeaconBlock < E > ,
3070
+ blobs : impl Iterator < Item = & ' a Blob < E > > ,
3071
+ proofs : impl Iterator < Item = & ' a KzgProof > ,
3072
+ custody_columns_opt : Option < HashSet < ColumnIndex > > ,
3073
+ ) {
3074
+ let is_peerdas_enabled = self . chain . spec . is_peer_das_enabled_for_epoch ( block. epoch ( ) ) ;
3075
+ if is_peerdas_enabled {
3076
+ let sidecars = blobs_to_data_column_sidecars (
3077
+ & blobs. collect :: < Vec < _ > > ( ) ,
3078
+ block,
3079
+ & self . chain . kzg ,
3080
+ & self . spec ,
3081
+ )
3082
+ . unwrap ( ) ;
3083
+
3084
+ let custody_columns = custody_columns_opt. unwrap_or_else ( || {
3085
+ let spec = & self . chain . spec ;
3086
+ let sampling_size = spec. sampling_size ( spec. custody_requirement ) . unwrap ( ) ;
3087
+ ( 0 ..sampling_size) . collect ( )
3088
+ } ) ;
3089
+
3090
+ let verified_columns = sidecars
3091
+ . into_iter ( )
3092
+ . filter ( |c| custody_columns. contains ( & c. index ) )
3093
+ . map ( |sidecar| {
3094
+ let column_index = sidecar. index ;
3095
+ self . chain
3096
+ . verify_data_column_sidecar_for_gossip ( sidecar, column_index)
3097
+ } )
3098
+ . collect :: < Result < Vec < _ > , _ > > ( )
3099
+ . unwrap ( ) ;
3100
+
3101
+ self . chain
3102
+ . process_gossip_data_columns ( verified_columns, || Ok ( ( ) ) )
3103
+ . await
3104
+ . unwrap ( ) ;
3105
+ } else {
3106
+ for ( i, ( kzg_proof, blob) ) in proofs. into_iter ( ) . zip ( blobs) . enumerate ( ) {
3107
+ let sidecar =
3108
+ Arc :: new ( BlobSidecar :: new ( i, blob. clone ( ) , block, * kzg_proof) . unwrap ( ) ) ;
3109
+ let gossip_blob = GossipVerifiedBlob :: new ( sidecar, i as u64 , & self . chain )
3110
+ . expect ( "should obtain gossip verified blob" ) ;
3111
+ self . chain
3112
+ . process_gossip_blob ( gossip_blob)
3113
+ . await
3114
+ . expect ( "should import valid gossip verified blob" ) ;
3115
+ }
3116
+ }
3117
+ }
2994
3118
}
2995
3119
2996
3120
// Junk `Debug` impl to satistfy certain trait bounds during testing.
0 commit comments