@@ -32,6 +32,7 @@ import (
32
32
"github.com/ethereum/go-ethereum/beacon/types"
33
33
"github.com/ethereum/go-ethereum/common"
34
34
"github.com/ethereum/go-ethereum/common/hexutil"
35
+ "github.com/ethereum/go-ethereum/log"
35
36
)
36
37
37
38
var (
@@ -184,46 +185,56 @@ func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64
184
185
return updates , committees , nil
185
186
}
186
187
187
- // GetOptimisticHeadUpdate fetches a signed header based on the latest available
188
- // optimistic update. Note that the signature should be verified by the caller
189
- // as its validity depends on the update chain.
188
+ // GetOptimisticUpdate fetches the latest available optimistic update.
189
+ // Note that the signature should be verified by the caller as its validity
190
+ // depends on the update chain.
190
191
//
191
192
// See data structure definition here:
192
193
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate
193
- func (api * BeaconLightApi ) GetOptimisticHeadUpdate () (types.SignedHeader , error ) {
194
+ func (api * BeaconLightApi ) GetOptimisticUpdate () (types.OptimisticUpdate , error ) {
194
195
resp , err := api .httpGet ("/eth/v1/beacon/light_client/optimistic_update" )
195
196
if err != nil {
196
- return types.SignedHeader {}, err
197
+ return types.OptimisticUpdate {}, err
197
198
}
198
- return decodeOptimisticHeadUpdate (resp )
199
+ return decodeOptimisticUpdate (resp )
199
200
}
200
201
201
- func decodeOptimisticHeadUpdate (enc []byte ) (types.SignedHeader , error ) {
202
+ func decodeOptimisticUpdate (enc []byte ) (types.OptimisticUpdate , error ) {
202
203
var data struct {
203
- Data struct {
204
- Header jsonBeaconHeader `json:"attested_header"`
205
- Aggregate types.SyncAggregate `json:"sync_aggregate"`
206
- SignatureSlot common.Decimal `json:"signature_slot"`
204
+ Version string
205
+ Data struct {
206
+ Attested jsonHeaderWithExecProof `json:"attested_header"`
207
+ Aggregate types.SyncAggregate `json:"sync_aggregate"`
208
+ SignatureSlot common.Decimal `json:"signature_slot"`
207
209
} `json:"data"`
208
210
}
209
211
if err := json .Unmarshal (enc , & data ); err != nil {
210
- return types.SignedHeader {}, err
212
+ return types.OptimisticUpdate {}, err
213
+ }
214
+ // Decode the execution payload headers.
215
+ attestedExecHeader , err := types .ExecutionHeaderFromJSON (data .Version , data .Data .Attested .Execution )
216
+ if err != nil {
217
+ return types.OptimisticUpdate {}, fmt .Errorf ("invalid attested header: %v" , err )
211
218
}
212
- if data .Data .Header .Beacon .StateRoot == (common.Hash {}) {
219
+ if data .Data .Attested .Beacon .StateRoot == (common.Hash {}) {
213
220
// workaround for different event encoding format in Lodestar
214
221
if err := json .Unmarshal (enc , & data .Data ); err != nil {
215
- return types.SignedHeader {}, err
222
+ return types.OptimisticUpdate {}, err
216
223
}
217
224
}
218
225
219
226
if len (data .Data .Aggregate .Signers ) != params .SyncCommitteeBitmaskSize {
220
- return types.SignedHeader {}, errors .New ("invalid sync_committee_bits length" )
227
+ return types.OptimisticUpdate {}, errors .New ("invalid sync_committee_bits length" )
221
228
}
222
229
if len (data .Data .Aggregate .Signature ) != params .BLSSignatureSize {
223
- return types.SignedHeader {}, errors .New ("invalid sync_committee_signature length" )
230
+ return types.OptimisticUpdate {}, errors .New ("invalid sync_committee_signature length" )
224
231
}
225
- return types.SignedHeader {
226
- Header : data .Data .Header .Beacon ,
232
+ return types.OptimisticUpdate {
233
+ Attested : types.HeaderWithExecProof {
234
+ Header : data .Data .Attested .Beacon ,
235
+ PayloadHeader : attestedExecHeader ,
236
+ PayloadBranch : data .Data .Attested .ExecutionBranch ,
237
+ },
227
238
Signature : data .Data .Aggregate ,
228
239
SignatureSlot : uint64 (data .Data .SignatureSlot ),
229
240
}, nil
@@ -411,7 +422,7 @@ func decodeHeadEvent(enc []byte) (uint64, common.Hash, error) {
411
422
412
423
type HeadEventListener struct {
413
424
OnNewHead func (slot uint64 , blockRoot common.Hash )
414
- OnSignedHead func (head types.SignedHeader )
425
+ OnOptimistic func (head types.OptimisticUpdate )
415
426
OnFinality func (head types.FinalityUpdate )
416
427
OnError func (err error )
417
428
}
@@ -449,21 +460,35 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func()
449
460
defer wg .Done ()
450
461
451
462
// Request initial data.
463
+ log .Trace ("Requesting initial head header" )
452
464
if head , _ , _ , err := api .GetHeader (common.Hash {}); err == nil {
465
+ log .Trace ("Retrieved initial head header" , "slot" , head .Slot , "hash" , head .Hash ())
453
466
listener .OnNewHead (head .Slot , head .Hash ())
467
+ } else {
468
+ log .Debug ("Failed to retrieve initial head header" , "error" , err )
454
469
}
455
- if signedHead , err := api .GetOptimisticHeadUpdate (); err == nil {
456
- listener .OnSignedHead (signedHead )
470
+ log .Trace ("Requesting initial optimistic update" )
471
+ if optimisticUpdate , err := api .GetOptimisticUpdate (); err == nil {
472
+ log .Trace ("Retrieved initial optimistic update" , "slot" , optimisticUpdate .Attested .Slot , "hash" , optimisticUpdate .Attested .Hash ())
473
+ listener .OnOptimistic (optimisticUpdate )
474
+ } else {
475
+ log .Debug ("Failed to retrieve initial optimistic update" , "error" , err )
457
476
}
477
+ log .Trace ("Requesting initial finality update" )
458
478
if finalityUpdate , err := api .GetFinalityUpdate (); err == nil {
479
+ log .Trace ("Retrieved initial finality update" , "slot" , finalityUpdate .Finalized .Slot , "hash" , finalityUpdate .Finalized .Hash ())
459
480
listener .OnFinality (finalityUpdate )
481
+ } else {
482
+ log .Debug ("Failed to retrieve initial finality update" , "error" , err )
460
483
}
461
484
485
+ log .Trace ("Starting event stream processing loop" )
462
486
// Receive the stream.
463
487
var stream * eventsource.Stream
464
488
select {
465
489
case stream = <- streamCh :
466
490
case <- ctx .Done ():
491
+ log .Trace ("Stopping event stream processing loop" )
467
492
return
468
493
}
469
494
@@ -474,8 +499,10 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func()
474
499
475
500
case event , ok := <- stream .Events :
476
501
if ! ok {
502
+ log .Trace ("Event stream closed" )
477
503
return
478
504
}
505
+ log .Trace ("New event received from event stream" , "type" , event .Event ())
479
506
switch event .Event () {
480
507
case "head" :
481
508
slot , blockRoot , err := decodeHeadEvent ([]byte (event .Data ()))
@@ -485,9 +512,9 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func()
485
512
listener .OnError (fmt .Errorf ("error decoding head event: %v" , err ))
486
513
}
487
514
case "light_client_optimistic_update" :
488
- signedHead , err := decodeOptimisticHeadUpdate ([]byte (event .Data ()))
515
+ optimisticUpdate , err := decodeOptimisticUpdate ([]byte (event .Data ()))
489
516
if err == nil {
490
- listener .OnSignedHead ( signedHead )
517
+ listener .OnOptimistic ( optimisticUpdate )
491
518
} else {
492
519
listener .OnError (fmt .Errorf ("error decoding optimistic update event: %v" , err ))
493
520
}
@@ -521,7 +548,8 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func()
521
548
// established. It can only return nil when the context is canceled.
522
549
func (api * BeaconLightApi ) startEventStream (ctx context.Context , listener * HeadEventListener ) * eventsource.Stream {
523
550
for retry := true ; retry ; retry = ctxSleep (ctx , 5 * time .Second ) {
524
- path := "/eth/v1/events?topics=head&topics=light_client_optimistic_update&topics=light_client_finality_update"
551
+ path := "/eth/v1/events?topics=head&topics=light_client_finality_update&topics=light_client_optimistic_update"
552
+ log .Trace ("Sending event subscription request" )
525
553
req , err := http .NewRequestWithContext (ctx , "GET" , api .url + path , nil )
526
554
if err != nil {
527
555
listener .OnError (fmt .Errorf ("error creating event subscription request: %v" , err ))
@@ -535,6 +563,7 @@ func (api *BeaconLightApi) startEventStream(ctx context.Context, listener *HeadE
535
563
listener .OnError (fmt .Errorf ("error creating event subscription: %v" , err ))
536
564
continue
537
565
}
566
+ log .Trace ("Successfully created event stream" )
538
567
return stream
539
568
}
540
569
return nil
0 commit comments