github.com/celestiaorg/celestia-node@v0.15.0-beta.1/nodebuilder/header/service.go (about) 1 package header 2 3 import ( 4 "context" 5 "fmt" 6 7 libhead "github.com/celestiaorg/go-header" 8 "github.com/celestiaorg/go-header/p2p" 9 "github.com/celestiaorg/go-header/sync" 10 11 "github.com/celestiaorg/celestia-node/header" 12 ) 13 14 // Service represents the header Service that can be started / stopped on a node. 15 // Service's main function is to manage its sub-services. Service can contain several 16 // sub-services, such as Exchange, ExchangeServer, Syncer, and so forth. 17 type Service struct { 18 ex libhead.Exchange[*header.ExtendedHeader] 19 20 syncer syncer 21 sub libhead.Subscriber[*header.ExtendedHeader] 22 p2pServer *p2p.ExchangeServer[*header.ExtendedHeader] 23 store libhead.Store[*header.ExtendedHeader] 24 } 25 26 // syncer bare minimum Syncer interface for testing 27 type syncer interface { 28 libhead.Head[*header.ExtendedHeader] 29 30 State() sync.State 31 SyncWait(ctx context.Context) error 32 } 33 34 // newHeaderService creates a new instance of header Service. 35 func newHeaderService( 36 syncer *sync.Syncer[*header.ExtendedHeader], 37 sub libhead.Subscriber[*header.ExtendedHeader], 38 p2pServer *p2p.ExchangeServer[*header.ExtendedHeader], 39 ex libhead.Exchange[*header.ExtendedHeader], 40 store libhead.Store[*header.ExtendedHeader], 41 ) Module { 42 return &Service{ 43 syncer: syncer, 44 sub: sub, 45 p2pServer: p2pServer, 46 ex: ex, 47 store: store, 48 } 49 } 50 51 func (s *Service) GetByHash(ctx context.Context, hash libhead.Hash) (*header.ExtendedHeader, error) { 52 return s.store.Get(ctx, hash) 53 } 54 55 func (s *Service) GetRangeByHeight( 56 ctx context.Context, 57 from *header.ExtendedHeader, 58 to uint64, 59 ) ([]*header.ExtendedHeader, error) { 60 return s.store.GetRangeByHeight(ctx, from, to) 61 } 62 63 func (s *Service) GetByHeight(ctx context.Context, height uint64) (*header.ExtendedHeader, error) { 64 head, err := s.syncer.Head(ctx) 65 switch { 66 case err != nil: 67 return nil, err 68 case head.Height() == height: 69 return head, nil 70 case head.Height()+1 < height: 71 return nil, fmt.Errorf("header: given height is from the future: "+ 72 "networkHeight: %d, requestedHeight: %d", head.Height(), height) 73 } 74 75 // TODO(vgonkivs): remove after https://github.com/celestiaorg/go-header/issues/32 is 76 // implemented and fetch header from HeaderEx if missing locally 77 head, err = s.store.Head(ctx) 78 switch { 79 case err != nil: 80 return nil, err 81 case head.Height() == height: 82 return head, nil 83 // `+1` allows for one header network lag, e.g. user request header that is milliseconds away 84 case head.Height()+1 < height: 85 return nil, fmt.Errorf("header: syncing in progress: "+ 86 "localHeadHeight: %d, requestedHeight: %d", head.Height(), height) 87 default: 88 return s.store.GetByHeight(ctx, height) 89 } 90 } 91 92 func (s *Service) WaitForHeight(ctx context.Context, height uint64) (*header.ExtendedHeader, error) { 93 return s.store.GetByHeight(ctx, height) 94 } 95 96 func (s *Service) LocalHead(ctx context.Context) (*header.ExtendedHeader, error) { 97 return s.store.Head(ctx) 98 } 99 100 func (s *Service) SyncState(context.Context) (sync.State, error) { 101 return s.syncer.State(), nil 102 } 103 104 func (s *Service) SyncWait(ctx context.Context) error { 105 return s.syncer.SyncWait(ctx) 106 } 107 108 func (s *Service) NetworkHead(ctx context.Context) (*header.ExtendedHeader, error) { 109 return s.syncer.Head(ctx) 110 } 111 112 func (s *Service) Subscribe(ctx context.Context) (<-chan *header.ExtendedHeader, error) { 113 subscription, err := s.sub.Subscribe() 114 if err != nil { 115 return nil, err 116 } 117 118 headerCh := make(chan *header.ExtendedHeader) 119 go func() { 120 defer close(headerCh) 121 defer subscription.Cancel() 122 123 for { 124 h, err := subscription.NextHeader(ctx) 125 if err != nil { 126 if err != context.DeadlineExceeded && err != context.Canceled { 127 log.Errorw("fetching header from subscription", "err", err) 128 } 129 return 130 } 131 132 select { 133 case <-ctx.Done(): 134 return 135 case headerCh <- h: 136 } 137 } 138 }() 139 return headerCh, nil 140 }