github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/sync/service_test.go (about)

     1  package sync
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  	"testing"
     7  	"time"
     8  
     9  	gcache "github.com/patrickmn/go-cache"
    10  	mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
    11  	"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
    12  	statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
    13  	p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
    14  	"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
    15  	mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing"
    16  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    17  	"github.com/prysmaticlabs/prysm/shared/abool"
    18  	"github.com/prysmaticlabs/prysm/shared/bls"
    19  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    20  	"github.com/prysmaticlabs/prysm/shared/testutil"
    21  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    22  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    23  )
    24  
    25  func TestService_StatusZeroEpoch(t *testing.T) {
    26  	bState, err := v1.InitializeFromProto(&pb.BeaconState{Slot: 0})
    27  	require.NoError(t, err)
    28  	r := &Service{
    29  		cfg: &Config{
    30  			P2P:         p2ptest.NewTestP2P(t),
    31  			InitialSync: new(mockSync.Sync),
    32  			Chain: &mockChain.ChainService{
    33  				Genesis: time.Now(),
    34  				State:   bState,
    35  			},
    36  		},
    37  		chainStarted: abool.New(),
    38  	}
    39  	r.chainStarted.Set()
    40  
    41  	assert.NoError(t, r.Status(), "Wanted non failing status")
    42  }
    43  
    44  func TestSyncHandlers_WaitToSync(t *testing.T) {
    45  	p2p := p2ptest.NewTestP2P(t)
    46  	chainService := &mockChain.ChainService{
    47  		Genesis:        time.Now(),
    48  		ValidatorsRoot: [32]byte{'A'},
    49  	}
    50  	r := Service{
    51  		ctx: context.Background(),
    52  		cfg: &Config{
    53  			P2P:           p2p,
    54  			Chain:         chainService,
    55  			StateNotifier: chainService.StateNotifier(),
    56  			InitialSync:   &mockSync.Sync{IsSyncing: false},
    57  		},
    58  		chainStarted: abool.New(),
    59  	}
    60  
    61  	topic := "/eth2/%x/beacon_block"
    62  	go r.registerHandlers()
    63  	time.Sleep(100 * time.Millisecond)
    64  	i := r.cfg.StateNotifier.StateFeed().Send(&feed.Event{
    65  		Type: statefeed.Initialized,
    66  		Data: &statefeed.InitializedData{
    67  			StartTime: time.Now(),
    68  		},
    69  	})
    70  	if i == 0 {
    71  		t.Fatal("didn't send genesis time to subscribers")
    72  	}
    73  	b := []byte("sk")
    74  	b32 := bytesutil.ToBytes32(b)
    75  	sk, err := bls.SecretKeyFromBytes(b32[:])
    76  	require.NoError(t, err)
    77  
    78  	msg := testutil.NewBeaconBlock()
    79  	msg.Block.ParentRoot = testutil.Random32Bytes(t)
    80  	msg.Signature = sk.Sign([]byte("data")).Marshal()
    81  	p2p.ReceivePubSub(topic, msg)
    82  	// wait for chainstart to be sent
    83  	time.Sleep(400 * time.Millisecond)
    84  	require.Equal(t, true, r.chainStarted.IsSet(), "Did not receive chain start event.")
    85  }
    86  
    87  func TestSyncHandlers_WaitForChainStart(t *testing.T) {
    88  	p2p := p2ptest.NewTestP2P(t)
    89  	chainService := &mockChain.ChainService{
    90  		Genesis:        time.Now(),
    91  		ValidatorsRoot: [32]byte{'A'},
    92  	}
    93  	r := Service{
    94  		ctx: context.Background(),
    95  		cfg: &Config{
    96  			P2P:           p2p,
    97  			Chain:         chainService,
    98  			StateNotifier: chainService.StateNotifier(),
    99  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   100  		},
   101  		chainStarted:        abool.New(),
   102  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   103  	}
   104  
   105  	go r.registerHandlers()
   106  	time.Sleep(100 * time.Millisecond)
   107  	i := r.cfg.StateNotifier.StateFeed().Send(&feed.Event{
   108  		Type: statefeed.Initialized,
   109  		Data: &statefeed.InitializedData{
   110  			StartTime: time.Now().Add(2 * time.Second),
   111  		},
   112  	})
   113  	if i == 0 {
   114  		t.Fatal("didn't send genesis time to subscribers")
   115  	}
   116  	require.Equal(t, false, r.chainStarted.IsSet(), "Chainstart was marked prematurely")
   117  
   118  	// wait for chainstart to be sent
   119  	time.Sleep(3 * time.Second)
   120  	require.Equal(t, true, r.chainStarted.IsSet(), "Did not receive chain start event.")
   121  }
   122  
   123  func TestSyncHandlers_WaitTillSynced(t *testing.T) {
   124  	p2p := p2ptest.NewTestP2P(t)
   125  	chainService := &mockChain.ChainService{
   126  		Genesis:        time.Now(),
   127  		ValidatorsRoot: [32]byte{'A'},
   128  	}
   129  	r := Service{
   130  		ctx: context.Background(),
   131  		cfg: &Config{
   132  			P2P:           p2p,
   133  			Chain:         chainService,
   134  			StateNotifier: chainService.StateNotifier(),
   135  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   136  		},
   137  		chainStarted: abool.New(),
   138  	}
   139  
   140  	topic := "/eth2/%x/beacon_block"
   141  	go r.registerHandlers()
   142  	time.Sleep(100 * time.Millisecond)
   143  	i := r.cfg.StateNotifier.StateFeed().Send(&feed.Event{
   144  		Type: statefeed.Initialized,
   145  		Data: &statefeed.InitializedData{
   146  			StartTime: time.Now(),
   147  		},
   148  	})
   149  	if i == 0 {
   150  		t.Fatal("didn't send genesis time to subscribers")
   151  	}
   152  	b := []byte("sk")
   153  	b32 := bytesutil.ToBytes32(b)
   154  	sk, err := bls.SecretKeyFromBytes(b32[:])
   155  	require.NoError(t, err)
   156  
   157  	msg := testutil.NewBeaconBlock()
   158  	msg.Block.ParentRoot = testutil.Random32Bytes(t)
   159  	msg.Signature = sk.Sign([]byte("data")).Marshal()
   160  	p2p.Digest, err = r.forkDigest()
   161  	r.cfg.BlockNotifier = chainService.BlockNotifier()
   162  	blockChan := make(chan feed.Event, 1)
   163  	sub := r.cfg.BlockNotifier.BlockFeed().Subscribe(blockChan)
   164  
   165  	require.NoError(t, err)
   166  	p2p.ReceivePubSub(topic, msg)
   167  
   168  	// wait for chainstart to be sent
   169  	time.Sleep(2 * time.Second)
   170  	require.Equal(t, true, r.chainStarted.IsSet(), "Did not receive chain start event.")
   171  
   172  	assert.Equal(t, 0, len(blockChan), "block was received by sync service despite not being fully synced")
   173  
   174  	i = r.cfg.StateNotifier.StateFeed().Send(&feed.Event{
   175  		Type: statefeed.Synced,
   176  		Data: &statefeed.SyncedData{
   177  			StartTime: time.Now(),
   178  		},
   179  	})
   180  
   181  	if i == 0 {
   182  		t.Fatal("didn't send genesis time to sync event subscribers")
   183  	}
   184  
   185  	wg := new(sync.WaitGroup)
   186  	wg.Add(1)
   187  	go func() {
   188  		// Wait for block to be received by service.
   189  		<-blockChan
   190  		wg.Done()
   191  		sub.Unsubscribe()
   192  	}()
   193  
   194  	p2p.ReceivePubSub(topic, msg)
   195  	// wait for message to be sent
   196  	testutil.WaitTimeout(wg, 2*time.Second)
   197  }
   198  
   199  func TestSyncService_StopCleanly(t *testing.T) {
   200  	p2p := p2ptest.NewTestP2P(t)
   201  	chainService := &mockChain.ChainService{
   202  		Genesis:        time.Now(),
   203  		ValidatorsRoot: [32]byte{'A'},
   204  	}
   205  	ctx, cancel := context.WithCancel(context.Background())
   206  	r := Service{
   207  		ctx:    ctx,
   208  		cancel: cancel,
   209  		cfg: &Config{
   210  			P2P:           p2p,
   211  			Chain:         chainService,
   212  			StateNotifier: chainService.StateNotifier(),
   213  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   214  		},
   215  		chainStarted: abool.New(),
   216  	}
   217  
   218  	go r.registerHandlers()
   219  	time.Sleep(100 * time.Millisecond)
   220  	i := r.cfg.StateNotifier.StateFeed().Send(&feed.Event{
   221  		Type: statefeed.Initialized,
   222  		Data: &statefeed.InitializedData{
   223  			StartTime: time.Now(),
   224  		},
   225  	})
   226  	if i == 0 {
   227  		t.Fatal("didn't send genesis time to subscribers")
   228  	}
   229  
   230  	var err error
   231  	p2p.Digest, err = r.forkDigest()
   232  	require.NoError(t, err)
   233  
   234  	// wait for chainstart to be sent
   235  	time.Sleep(2 * time.Second)
   236  	require.Equal(t, true, r.chainStarted.IsSet(), "Did not receive chain start event.")
   237  
   238  	i = r.cfg.StateNotifier.StateFeed().Send(&feed.Event{
   239  		Type: statefeed.Synced,
   240  		Data: &statefeed.SyncedData{
   241  			StartTime: time.Now(),
   242  		},
   243  	})
   244  	if i == 0 {
   245  		t.Fatal("didn't send genesis time to sync event subscribers")
   246  	}
   247  
   248  	time.Sleep(1 * time.Second)
   249  
   250  	require.NotEqual(t, 0, len(r.cfg.P2P.PubSub().GetTopics()))
   251  	require.NotEqual(t, 0, len(r.cfg.P2P.Host().Mux().Protocols()))
   252  
   253  	// Both pubsub and rpc topcis should be unsubscribed.
   254  	require.NoError(t, r.Stop())
   255  
   256  	// Sleep to allow pubsub topics to be deregistered.
   257  	time.Sleep(1 * time.Second)
   258  	require.Equal(t, 0, len(r.cfg.P2P.PubSub().GetTopics()))
   259  	require.Equal(t, 0, len(r.cfg.P2P.Host().Mux().Protocols()))
   260  }