Skip to content

Commit 3dd46e8

Browse files
committed
add for sync node
1 parent ed89c2b commit 3dd46e8

5 files changed

Lines changed: 428 additions & 3 deletions

File tree

block/internal/executing/executor.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ func (e *Executor) produceBlock() error {
336336

337337
// fetch forced included txs
338338
forcedIncludedTxsEvent, err := e.daRetriever.RetrieveForcedIncludedTxsFromDA(e.ctx, currentState.DAHeight)
339-
if err != nil {
339+
if err != nil && !errors.Is(err, syncing.ErrForceInclusionNotConfigured) {
340340
e.logger.Error().Err(err).Msg("failed to retrieve forced included txs")
341341
}
342342

block/internal/syncing/da_retriever.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,14 @@ func (r *DARetriever) RetrieveFromDA(ctx context.Context, daHeight uint64) ([]co
9191
return r.processBlobs(ctx, blobsResp.Data, daHeight), nil
9292
}
9393

94+
// ErrForceInclusionNotConfigured is returned when the forced inclusion namespace is not configured.
95+
var ErrForceInclusionNotConfigured = errors.New("forced inclusion namespace not configured")
96+
9497
// RetrieveForcedIncludedTxsFromDA retrieves forced inclusion transactions from the DA layer.
9598
// It fetches from the daHeight for the da epoch range defined in the config.
9699
func (r *DARetriever) RetrieveForcedIncludedTxsFromDA(ctx context.Context, daHeight uint64) (*common.ForcedIncludedEvent, error) {
97100
if !r.hasForcedInclusionNs {
98-
return nil, fmt.Errorf("forced inclusion namespace not configured")
101+
return nil, ErrForceInclusionNotConfigured
99102
}
100103

101104
event := &common.ForcedIncludedEvent{

block/internal/syncing/syncer.go

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import (
55
"context"
66
"errors"
77
"fmt"
8-
pubsub "github.com/libp2p/go-libp2p-pubsub"
98
"sync"
109
"sync/atomic"
1110
"time"
1211

12+
pubsub "github.com/libp2p/go-libp2p-pubsub"
13+
1314
"github.com/rs/zerolog"
1415
"golang.org/x/sync/errgroup"
1516

@@ -472,6 +473,12 @@ func (s *Syncer) trySyncNextBlock(event *common.DAHeightEvent) error {
472473
return err
473474
}
474475

476+
// Verify forced inclusion transactions if configured
477+
if err := s.verifyForcedInclusionTxs(currentState, data); err != nil {
478+
s.logger.Error().Err(err).Uint64("height", nextHeight).Msg("forced inclusion verification failed")
479+
// TODO(@julienrbrt): Eventually halt the syncer and request the node to be started using the based sequencer.
480+
}
481+
475482
// Apply block
476483
newState, err := s.applyBlock(header.Header, data, currentState)
477484
if err != nil {
@@ -589,6 +596,62 @@ func (s *Syncer) validateBlock(currState types.State, data *types.Data, header *
589596
return nil
590597
}
591598

599+
// verifyForcedInclusionTxs verifies that all forced inclusion transactions from DA are included in the block
600+
func (s *Syncer) verifyForcedInclusionTxs(currentState types.State, data *types.Data) error {
601+
if s.daRetriever == nil {
602+
return nil
603+
}
604+
605+
// Retrieve forced inclusion transactions from DA
606+
forcedIncludedTxsEvent, err := s.daRetriever.RetrieveForcedIncludedTxsFromDA(s.ctx, currentState.DAHeight)
607+
if err != nil {
608+
if errors.Is(err, ErrForceInclusionNotConfigured) {
609+
s.logger.Debug().Msg("forced inclusion namespace not configured, skipping verification")
610+
return nil
611+
}
612+
613+
return fmt.Errorf("failed to retrieve forced included txs from DA: %w", err)
614+
}
615+
616+
// If no forced inclusion transactions found, nothing to verify
617+
if len(forcedIncludedTxsEvent.Txs) == 0 {
618+
s.logger.Debug().Uint64("da_height", currentState.DAHeight).Msg("no forced inclusion transactions to verify")
619+
return nil
620+
}
621+
622+
blockTxMap := make(map[string]bool)
623+
for _, tx := range data.Txs {
624+
blockTxMap[string(tx)] = true
625+
}
626+
627+
// Check if all forced inclusion transactions are present in the block
628+
var missingTxs [][]byte
629+
for _, forcedTx := range forcedIncludedTxsEvent.Txs {
630+
if !blockTxMap[string(forcedTx)] {
631+
missingTxs = append(missingTxs, forcedTx)
632+
}
633+
}
634+
635+
if len(missingTxs) > 0 {
636+
s.logger.Error().
637+
Uint64("height", data.Height()).
638+
Uint64("da_height", currentState.DAHeight).
639+
Uint64("da_epoch_start", forcedIncludedTxsEvent.StartDaHeight).
640+
Uint64("da_epoch_end", forcedIncludedTxsEvent.EndDaHeight).
641+
Int("missing_count", len(missingTxs)).
642+
Int("total_forced", len(forcedIncludedTxsEvent.Txs)).
643+
Msg("SEQUENCER IS MALICIOUS: forced inclusion transactions missing from block")
644+
return fmt.Errorf("sequencer is malicious: %d forced inclusion transactions not included in block", len(missingTxs))
645+
}
646+
647+
s.logger.Debug().
648+
Uint64("height", data.Height()).
649+
Int("forced_txs", len(forcedIncludedTxsEvent.Txs)).
650+
Msg("all forced inclusion transactions verified in block")
651+
652+
return nil
653+
}
654+
592655
// sendCriticalError sends a critical error to the error channel without blocking
593656
func (s *Syncer) sendCriticalError(err error) {
594657
if s.errorCh != nil {

0 commit comments

Comments
 (0)