1
1
import { fromHexString , toHexString } from "@chainsafe/ssz" ;
2
2
import { routes , ServerApi , ResponseFormat } from "@lodestar/api" ;
3
- import { computeTimeAtSlot , signedBlindedBlockToFull , signedBlindedBlobSidecarsToFull } from "@lodestar/state-transition" ;
3
+ import {
4
+ computeTimeAtSlot ,
5
+ parseSignedBlindedBlockOrContents ,
6
+ reconstructFullBlockOrContents ,
7
+ } from "@lodestar/state-transition" ;
4
8
import { SLOTS_PER_HISTORICAL_ROOT } from "@lodestar/params" ;
5
- import { sleep , toHex , LogDataBasic } from "@lodestar/utils" ;
6
- import { allForks , deneb , isSignedBlockContents , isSignedBlindedBlockContents } from "@lodestar/types" ;
9
+ import { sleep , toHex } from "@lodestar/utils" ;
10
+ import { allForks , deneb , isSignedBlockContents , ProducedBlockSource } from "@lodestar/types" ;
7
11
import { BlockSource , getBlockInput , ImportBlockOpts , BlockInput } from "../../../../chain/blocks/types.js" ;
8
12
import { promiseAllMaybeAsync } from "../../../../util/promises.js" ;
9
13
import { isOptimisticBlock } from "../../../../util/forkChoice.js" ;
@@ -15,11 +19,6 @@ import {resolveBlockId, toBeaconHeaderResponse} from "./utils.js";
15
19
16
20
type PublishBlockOpts = ImportBlockOpts & { broadcastValidation ?: routes . beacon . BroadcastValidation } ;
17
21
18
- type ParsedSignedBlindedBlockOrContents = {
19
- signedBlindedBlock : allForks . SignedBlindedBeaconBlock ;
20
- signedBlindedBlobSidecars : deneb . SignedBlindedBlobSidecars | null ;
21
- } ;
22
-
23
22
/**
24
23
* Validator clock may be advanced from beacon's clock. If the validator requests a resource in a
25
24
* future slot, wait some time instead of rejecting the request because it's in the future
@@ -152,27 +151,28 @@ export function getBeaconBlockApi({
152
151
. getBlindedForkTypes ( signedBlindedBlock . message . slot )
153
152
. BeaconBlock . hashTreeRoot ( signedBlindedBlock . message )
154
153
) ;
155
- const logCtx = { blockRoot, slot} ;
156
154
157
155
// Either the payload/blobs are cached from i) engine locally or ii) they are from the builder
158
156
//
159
- // executionPayload can be null or a real payload in locally produced, its only undefined when
160
- // the block came from the builder
161
- const executionPayload = chain . producedBlockRoot . get ( blockRoot ) ;
157
+ // executionPayload can be null or a real payload in locally produced so check for presence of root
158
+ const source = chain . producedBlockRoot . has ( blockRoot ) ? ProducedBlockSource . engine : ProducedBlockSource . builder ;
159
+
160
+ const executionPayload = chain . producedBlockRoot . get ( blockRoot ) ?? null ;
161
+ const blobSidecars = executionPayload
162
+ ? chain . producedBlobSidecarsCache . get ( toHex ( executionPayload . blockHash ) )
163
+ : undefined ;
164
+ const blobs = blobSidecars ? blobSidecars . map ( ( blobSidecar ) => blobSidecar . blob ) : null ;
165
+
162
166
const signedBlockOrContents =
163
- executionPayload !== undefined
164
- ? reconstructLocalBlockOrContents (
165
- chain ,
166
- { signedBlindedBlock, signedBlindedBlobSidecars} ,
167
- executionPayload ,
168
- logCtx
169
- )
170
- : await reconstructBuilderBlockOrContents ( chain , signedBlindedBlockOrContents , logCtx ) ;
167
+ source === ProducedBlockSource . engine
168
+ ? reconstructFullBlockOrContents ( { signedBlindedBlock, signedBlindedBlobSidecars} , { executionPayload, blobs} )
169
+ : await reconstructBuilderBlockOrContents ( chain , signedBlindedBlockOrContents ) ;
171
170
172
171
// the full block is published by relay and it's possible that the block is already known to us
173
172
// by gossip
174
173
//
175
174
// see: https://github.com/ChainSafe/lodestar/issues/5404
175
+ chain . logger . info ( "Publishing assembled block" , { blockRoot, slot, source} ) ;
176
176
return publishBlock ( signedBlockOrContents , { ...opts , ignoreIfKnown : true } ) ;
177
177
} ;
178
178
@@ -365,73 +365,15 @@ export function getBeaconBlockApi({
365
365
} ;
366
366
}
367
367
368
- function parseSignedBlindedBlockOrContents (
369
- signedBlindedBlockOrContents : allForks . SignedBlindedBeaconBlockOrContents
370
- ) : ParsedSignedBlindedBlockOrContents {
371
- if ( isSignedBlindedBlockContents ( signedBlindedBlockOrContents ) ) {
372
- const signedBlindedBlock = signedBlindedBlockOrContents . signedBlindedBlock ;
373
- const signedBlindedBlobSidecars = signedBlindedBlockOrContents . signedBlindedBlobSidecars ;
374
- return { signedBlindedBlock, signedBlindedBlobSidecars} ;
375
- } else {
376
- return { signedBlindedBlock : signedBlindedBlockOrContents , signedBlindedBlobSidecars : null } ;
377
- }
378
- }
379
-
380
- function reconstructLocalBlockOrContents (
381
- chain : ApiModules [ "chain" ] ,
382
- { signedBlindedBlock, signedBlindedBlobSidecars} : ParsedSignedBlindedBlockOrContents ,
383
- executionPayload : allForks . ExecutionPayload | null ,
384
- logCtx : Record < string , LogDataBasic >
385
- ) : allForks . SignedBeaconBlockOrContents {
386
- const signedBlock = signedBlindedBlockToFull ( signedBlindedBlock , executionPayload ) ;
387
- if ( executionPayload !== null ) {
388
- Object . assign ( logCtx , { transactions : executionPayload . transactions . length } ) ;
389
- }
390
-
391
- if ( signedBlindedBlobSidecars !== null ) {
392
- if ( executionPayload === null ) {
393
- throw Error ( "Missing locally produced executionPayload for deneb+ publishBlindedBlock" ) ;
394
- }
395
-
396
- const blockHash = toHex ( executionPayload . blockHash ) ;
397
- const blobSidecars = chain . producedBlobSidecarsCache . get ( blockHash ) ;
398
- if ( blobSidecars === undefined ) {
399
- throw Error ( "Missing blobSidecars from the local execution cache" ) ;
400
- }
401
- if ( blobSidecars . length !== signedBlindedBlobSidecars . length ) {
402
- throw Error (
403
- `Length mismatch signedBlindedBlobSidecars=${ signedBlindedBlobSidecars . length } blobSidecars=${ blobSidecars . length } `
404
- ) ;
405
- }
406
- const signedBlobSidecars = signedBlindedBlobSidecarsToFull (
407
- signedBlindedBlobSidecars ,
408
- blobSidecars . map ( ( blobSidecar ) => blobSidecar . blob )
409
- ) ;
410
-
411
- Object . assign ( logCtx , { blobs : signedBlindedBlobSidecars . length } ) ;
412
- chain . logger . verbose ( "Block & blobs assembled from locally cached payload" , logCtx ) ;
413
- return { signedBlock, signedBlobSidecars} as allForks . SignedBeaconBlockOrContents ;
414
- } else {
415
- chain . logger . verbose ( "Block assembled from locally cached payload" , logCtx ) ;
416
- return signedBlock as allForks . SignedBeaconBlockOrContents ;
417
- }
418
- }
419
-
420
368
async function reconstructBuilderBlockOrContents (
421
369
chain : ApiModules [ "chain" ] ,
422
- signedBlindedBlockOrContents : allForks . SignedBlindedBeaconBlockOrContents ,
423
- logCtx : Record < string , LogDataBasic >
370
+ signedBlindedBlockOrContents : allForks . SignedBlindedBeaconBlockOrContents
424
371
) : Promise < allForks . SignedBeaconBlockOrContents > {
425
- // Mechanism for blobs & blocks on builder is implemenented separately in a followup deneb-builder PR
426
- if ( isSignedBlindedBlockContents ( signedBlindedBlockOrContents ) ) {
427
- throw Error ( "exeutionBuilder not yet implemented for deneb+ forks" ) ;
428
- }
429
372
const executionBuilder = chain . executionBuilder ;
430
373
if ( ! executionBuilder ) {
431
374
throw Error ( "exeutionBuilder required to publish SignedBlindedBeaconBlock" ) ;
432
375
}
433
376
434
377
const signedBlockOrContents = await executionBuilder . submitBlindedBlock ( signedBlindedBlockOrContents ) ;
435
- chain . logger . verbose ( "Publishing block assembled from the builder" , logCtx ) ;
436
378
return signedBlockOrContents ;
437
379
}
0 commit comments