github.com/amazechain/amc@v0.1.3/internal/sync/service.go (about) 1 // Package sync includes all chain-synchronization logic for the AmazeChain node, 2 // including gossip-sub blocks, txs, and other p2p 3 // messages, as well as ability to process and respond to block requests 4 // by peers. 5 package sync 6 7 import ( 8 "context" 9 "github.com/amazechain/amc/common" 10 block2 "github.com/amazechain/amc/common/block" 11 "github.com/amazechain/amc/common/types" 12 "github.com/amazechain/amc/internal/p2p" 13 "github.com/amazechain/amc/utils" 14 lru "github.com/hashicorp/golang-lru/v2" 15 "sync" 16 "time" 17 18 pubsub "github.com/libp2p/go-libp2p-pubsub" 19 "github.com/libp2p/go-libp2p/core/peer" 20 "github.com/libp2p/go-libp2p/core/protocol" 21 "github.com/pkg/errors" 22 ) 23 24 const rangeLimit = 1024 25 const seenBlockSize = 1000 26 const badBlockSize = 1000 27 const syncMetricsInterval = 10 * time.Second 28 29 // todo 30 const ttfbTimeout = 10 * time.Second // TtfbTimeout is the maximum time to wait for first byte of request response (time-to-first-byte). 31 const respTimeout = 20 * time.Second // RespTimeout is the maximum time for complete response transfer. 32 33 // todo 34 const maxRequestBlocks = 1024 35 36 const maintainPeerStatusesInterval = 2 * time.Minute 37 38 const resyncInterval = 1 * time.Minute 39 40 const enableFullSSZDataLogging = false 41 42 var ( 43 // Seconds in one block. 44 pendingBlockExpTime = 8 * time.Second 45 errWrongMessage = errors.New("wrong pubsub message") 46 errNilMessage = errors.New("nil pubsub message") 47 ) 48 49 // Common type for functional p2p validation options. 50 type validationFn func(ctx context.Context) (pubsub.ValidationResult, error) 51 52 // config to hold dependencies for the sync service. 53 type config struct { 54 p2p p2p.P2P 55 chain common.IBlockChain 56 initialSync Checker 57 } 58 59 // This defines the interface for interacting with block chain service 60 type blockchainService interface { 61 } 62 63 // Service is responsible for handling all run time p2p related operations as the 64 // main entry point for network messages. 65 type Service struct { 66 cfg *config 67 ctx context.Context 68 cancel context.CancelFunc 69 70 subHandler *subTopicHandler 71 rateLimiter *limiter 72 73 seenBlockCache *lru.Cache[types.Hash, *block2.Block] 74 seenBlockLock sync.RWMutex 75 badBlockLock sync.RWMutex 76 badBlockCache *lru.Cache[types.Hash, bool] 77 78 validateBlockLock sync.RWMutex 79 seenExitLock sync.RWMutex 80 seenSyncMessageLock sync.RWMutex 81 seenSyncContributionLock sync.RWMutex 82 syncContributionBitsOverlapLock sync.RWMutex 83 } 84 85 // NewService initializes new regular sync service. 86 func NewService(ctx context.Context, opts ...Option) *Service { 87 ctx, cancel := context.WithCancel(ctx) 88 r := &Service{ 89 ctx: ctx, 90 cancel: cancel, 91 cfg: &config{}, 92 } 93 94 for _, opt := range opts { 95 if err := opt(r); err != nil { 96 return nil 97 } 98 } 99 100 r.subHandler = newSubTopicHandler() 101 r.rateLimiter = newRateLimiter(r.cfg.p2p) 102 r.initCaches() 103 104 r.registerRPCHandlers() 105 106 digest, err := r.currentForkDigest() 107 if err != nil { 108 panic("Could not retrieve current fork digest") 109 } 110 r.registerSubscribers(digest) 111 //go r.forkWatcher() 112 113 return r 114 } 115 116 // Start the regular sync service. 117 func (s *Service) Start() { 118 s.cfg.p2p.AddConnectionHandler(s.reValidatePeer, s.sendGoodbye) 119 s.cfg.p2p.AddDisconnectionHandler(func(_ context.Context, p peer.ID) error { 120 // no-op 121 //for no reason disconnect 122 //todo 123 if nextValidTime, err := s.cfg.p2p.Peers().NextValidTime(p); err == nil && time.Now().After(nextValidTime) { 124 s.cfg.p2p.Peers().SetNextValidTime(p, time.Now().Add(10*time.Minute)) 125 } 126 return nil 127 }) 128 s.cfg.p2p.AddPingMethod(s.sendPingRequest) 129 s.maintainPeerStatuses() 130 s.resyncIfBehind() 131 132 // Update sync metrics. 133 utils.RunEvery(s.ctx, syncMetricsInterval, s.updateMetrics) 134 } 135 136 // Stop the regular sync service. 137 func (s *Service) Stop() error { 138 defer func() { 139 if s.rateLimiter != nil { 140 s.rateLimiter.free() 141 } 142 }() 143 // Removing RPC Stream handlers. 144 for _, p := range s.cfg.p2p.Host().Mux().Protocols() { 145 s.cfg.p2p.Host().RemoveStreamHandler(protocol.ID(p)) 146 } 147 // Deregister Topic Subscribers. 148 for _, t := range s.cfg.p2p.PubSub().GetTopics() { 149 s.unSubscribeFromTopic(t) 150 } 151 defer s.cancel() 152 return nil 153 } 154 155 // Status of the currently running regular sync service. 156 func (s *Service) Status() error { 157 // If our HighestBlockNumber lower than our peers are reporting then we might be out of sync. 158 if s.cfg.chain.CurrentBlock().Number64().Uint64()+1 < s.cfg.p2p.Peers().HighestBlockNumber().Uint64() { 159 return errors.New("out of sync") 160 } 161 return nil 162 } 163 164 // This initializes the caches to update seen beacon objects coming in from the wire 165 // and prevent DoS. 166 func (s *Service) initCaches() { 167 s.badBlockCache, _ = lru.New[types.Hash, bool](seenBlockSize) 168 s.seenBlockCache, _ = lru.New[types.Hash, *block2.Block](badBlockSize) 169 } 170 171 // marks the chain as having started. 172 func (s *Service) markForChainStart() { 173 //s.chainStarted.Set() 174 } 175 176 // Checker defines a struct which can verify whether a node is currently 177 // synchronizing a chain with the rest of peers in the network. 178 type Checker interface { 179 Syncing() bool 180 Synced() bool 181 Status() error 182 Resync() error 183 }