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  }