github.com/status-im/status-go@v1.1.0/protocol/transport/envelopes_monitor_test.go (about)

     1  package transport
     2  
     3  import (
     4  	"context"
     5  	"reflect"
     6  	"testing"
     7  	"time"
     8  
     9  	"go.uber.org/zap"
    10  
    11  	"github.com/stretchr/testify/suite"
    12  
    13  	"github.com/ethereum/go-ethereum/p2p/enode"
    14  
    15  	"github.com/status-im/status-go/eth-node/crypto"
    16  	"github.com/status-im/status-go/eth-node/types"
    17  )
    18  
    19  var (
    20  	testHash   = types.Hash{0x01}
    21  	testHashes = []types.Hash{testHash}
    22  	testIDs    = [][]byte{[]byte("id")}
    23  )
    24  
    25  type envelopeEventsHandlerMock struct {
    26  	envelopeSentCalls [][][]byte // slice of EnvelopeSent arguments
    27  }
    28  
    29  func (h *envelopeEventsHandlerMock) EnvelopeSent(identifiers [][]byte) {
    30  	h.envelopeSentCalls = append(h.envelopeSentCalls, identifiers)
    31  }
    32  func (h *envelopeEventsHandlerMock) EnvelopeExpired([][]byte, error) {
    33  }
    34  func (h *envelopeEventsHandlerMock) MailServerRequestCompleted(types.Hash, types.Hash, []byte, error) {
    35  }
    36  func (h *envelopeEventsHandlerMock) MailServerRequestExpired(types.Hash) {
    37  }
    38  
    39  type EnvelopesMonitorSuite struct {
    40  	suite.Suite
    41  
    42  	monitor           *EnvelopesMonitor
    43  	eventsHandlerMock *envelopeEventsHandlerMock
    44  }
    45  
    46  func TestEnvelopesMonitorSuite(t *testing.T) {
    47  	suite.Run(t, new(EnvelopesMonitorSuite))
    48  }
    49  
    50  func (s *EnvelopesMonitorSuite) SetupTest() {
    51  	s.eventsHandlerMock = &envelopeEventsHandlerMock{}
    52  	s.monitor = NewEnvelopesMonitor(
    53  		nil,
    54  		EnvelopesMonitorConfig{
    55  			EnvelopeEventsHandler:            s.eventsHandlerMock,
    56  			MaxAttempts:                      6,
    57  			AwaitOnlyMailServerConfirmations: false,
    58  			IsMailserver:                     func(types.EnodeID) bool { return false },
    59  			Logger:                           zap.NewNop(),
    60  		},
    61  	)
    62  }
    63  
    64  func (s *EnvelopesMonitorSuite) TestEnvelopePosted() {
    65  	err := s.monitor.Add(testIDs, testHashes, []*types.NewMessage{{}})
    66  	s.Require().NoError(err)
    67  	s.Contains(s.monitor.envelopes, testHash)
    68  	s.Equal(EnvelopePosted, s.monitor.envelopes[testHash].state)
    69  	s.monitor.handleEvent(types.EnvelopeEvent{
    70  		Event: types.EventEnvelopeSent,
    71  		Hash:  testHash,
    72  	})
    73  	s.Contains(s.monitor.envelopes, testHash)
    74  	s.Equal(EnvelopeSent, s.monitor.envelopes[testHash].state)
    75  }
    76  
    77  func (s *EnvelopesMonitorSuite) TestEnvelopePostedOutOfOrder() {
    78  	s.monitor.handleEvent(types.EnvelopeEvent{
    79  		Event: types.EventEnvelopeSent,
    80  		Hash:  testHash,
    81  	})
    82  
    83  	err := s.monitor.Add(testIDs, testHashes, []*types.NewMessage{{}})
    84  	s.Require().NoError(err)
    85  	s.Require().Contains(s.monitor.envelopes, testHash)
    86  	s.Require().Equal(EnvelopeSent, s.monitor.envelopes[testHash].state)
    87  }
    88  
    89  func (s *EnvelopesMonitorSuite) TestConfirmedWithAcknowledge() {
    90  	testBatch := types.Hash{1}
    91  	pkey, err := crypto.GenerateKey()
    92  	s.Require().NoError(err)
    93  	node := enode.NewV4(&pkey.PublicKey, nil, 0, 0)
    94  	err = s.monitor.Add(testIDs, testHashes, []*types.NewMessage{{}})
    95  	s.Require().NoError(err)
    96  	s.Contains(s.monitor.envelopes, testHash)
    97  	s.Equal(EnvelopePosted, s.monitor.envelopes[testHash].state)
    98  	s.monitor.handleEvent(types.EnvelopeEvent{
    99  		Event: types.EventEnvelopeSent,
   100  		Hash:  testHash,
   101  		Batch: testBatch,
   102  	})
   103  	s.Equal(EnvelopePosted, s.monitor.envelopes[testHash].state)
   104  	s.monitor.handleEvent(types.EnvelopeEvent{
   105  		Event: types.EventBatchAcknowledged,
   106  		Batch: testBatch,
   107  		Peer:  types.EnodeID(node.ID()),
   108  	})
   109  	s.Contains(s.monitor.envelopes, testHash)
   110  	s.Equal(EnvelopeSent, s.monitor.envelopes[testHash].state)
   111  }
   112  
   113  func (s *EnvelopesMonitorSuite) TestRemoved() {
   114  	err := s.monitor.Add(testIDs, testHashes, []*types.NewMessage{{}})
   115  	s.Require().NoError(err)
   116  	s.Contains(s.monitor.envelopes, testHash)
   117  	s.monitor.handleEvent(types.EnvelopeEvent{
   118  		Event: types.EventEnvelopeExpired,
   119  		Hash:  testHash,
   120  	})
   121  	s.NotContains(s.monitor.envelopes, testHash)
   122  }
   123  
   124  func (s *EnvelopesMonitorSuite) TestIgnoreNotFromMailserver() {
   125  	// enables filter in the tracker to drop confirmations from non-mailserver peers
   126  	s.monitor.awaitOnlyMailServerConfirmations = true
   127  	err := s.monitor.Add(testIDs, testHashes, []*types.NewMessage{{}})
   128  	s.Require().NoError(err)
   129  	s.monitor.handleEvent(types.EnvelopeEvent{
   130  		Event: types.EventEnvelopeSent,
   131  		Hash:  testHash,
   132  		Peer:  types.EnodeID{1}, // could be empty, doesn't impact test behaviour
   133  	})
   134  	s.Require().Equal(EnvelopePosted, s.monitor.GetState(testHash))
   135  }
   136  
   137  func (s *EnvelopesMonitorSuite) TestReceived() {
   138  	s.monitor.isMailserver = func(peer types.EnodeID) bool {
   139  		return true
   140  	}
   141  	err := s.monitor.Add(testIDs, testHashes, []*types.NewMessage{{}})
   142  	s.Require().NoError(err)
   143  	s.Contains(s.monitor.envelopes, testHash)
   144  	s.monitor.handleEvent(types.EnvelopeEvent{
   145  		Event: types.EventEnvelopeReceived,
   146  		Hash:  testHash,
   147  	})
   148  	s.Require().Equal(EnvelopeSent, s.monitor.GetState(testHash))
   149  }
   150  
   151  func (s *EnvelopesMonitorSuite) TestMultipleHashes() {
   152  	messageIDs := [][]byte{[]byte("id1"), []byte("id2")}
   153  	hashes := []types.Hash{{0x01}, {0x02}, {0x03}}
   154  	messages := []*types.NewMessage{{}, {}, {}}
   155  
   156  	err := s.monitor.Add(messageIDs, hashes, messages)
   157  	s.Require().NoError(err)
   158  	for _, hash := range hashes {
   159  		s.Contains(s.monitor.envelopes, hash)
   160  	}
   161  	s.Require().Empty(s.eventsHandlerMock.envelopeSentCalls)
   162  	s.Require().Equal(EnvelopePosted, s.monitor.envelopes[hashes[0]].state)
   163  	s.Require().Equal(EnvelopePosted, s.monitor.envelopes[hashes[1]].state)
   164  	s.Require().Equal(EnvelopePosted, s.monitor.envelopes[hashes[2]].state)
   165  
   166  	s.monitor.handleEvent(types.EnvelopeEvent{
   167  		Event: types.EventEnvelopeSent,
   168  		Hash:  hashes[0],
   169  	})
   170  	s.Require().Empty(s.eventsHandlerMock.envelopeSentCalls)
   171  	s.Require().Equal(EnvelopeSent, s.monitor.envelopes[hashes[0]].state)
   172  	s.Require().Equal(EnvelopePosted, s.monitor.envelopes[hashes[1]].state)
   173  	s.Require().Equal(EnvelopePosted, s.monitor.envelopes[hashes[2]].state)
   174  
   175  	s.monitor.handleEvent(types.EnvelopeEvent{
   176  		Event: types.EventEnvelopeSent,
   177  		Hash:  hashes[1],
   178  	})
   179  	s.Require().Empty(s.eventsHandlerMock.envelopeSentCalls)
   180  	s.Require().Equal(EnvelopeSent, s.monitor.envelopes[hashes[0]].state)
   181  	s.Require().Equal(EnvelopeSent, s.monitor.envelopes[hashes[1]].state)
   182  	s.Require().Equal(EnvelopePosted, s.monitor.envelopes[hashes[2]].state)
   183  
   184  	s.monitor.handleEvent(types.EnvelopeEvent{
   185  		Event: types.EventEnvelopeSent,
   186  		Hash:  hashes[2],
   187  	})
   188  	// Identifiers should be marked as sent only if all corresponding envelopes are sent
   189  	s.Require().Len(s.eventsHandlerMock.envelopeSentCalls, 1)
   190  	s.Require().True(reflect.DeepEqual(messageIDs, s.eventsHandlerMock.envelopeSentCalls[0]))
   191  	s.Require().Equal(EnvelopeSent, s.monitor.envelopes[hashes[0]].state)
   192  	s.Require().Equal(EnvelopeSent, s.monitor.envelopes[hashes[1]].state)
   193  	s.Require().Equal(EnvelopeSent, s.monitor.envelopes[hashes[2]].state)
   194  }
   195  
   196  func (s *EnvelopesMonitorSuite) TestMultipleHashes_EnvelopeExpired() {
   197  	messageIDs := [][]byte{[]byte("id1"), []byte("id2")}
   198  	hashes := []types.Hash{{0x01}, {0x02}, {0x03}}
   199  	messages := []*types.NewMessage{{}, {}, {}}
   200  
   201  	err := s.monitor.Add(messageIDs, hashes, messages)
   202  	s.Require().NoError(err)
   203  
   204  	// If any envelope fails, then messageIDs are considered as not sent
   205  	s.monitor.handleEvent(types.EnvelopeEvent{
   206  		Event: types.EventEnvelopeExpired,
   207  		Hash:  hashes[0],
   208  	})
   209  	s.monitor.handleEvent(types.EnvelopeEvent{
   210  		Event: types.EventEnvelopeSent,
   211  		Hash:  hashes[1],
   212  	})
   213  	s.monitor.handleEvent(types.EnvelopeEvent{
   214  		Event: types.EventEnvelopeSent,
   215  		Hash:  hashes[2],
   216  	})
   217  
   218  	s.Require().Empty(s.eventsHandlerMock.envelopeSentCalls)
   219  	s.Require().Empty(s.monitor.messageEnvelopeHashes)
   220  	s.Require().Len(s.monitor.envelopes, 2)
   221  }
   222  
   223  func (s *EnvelopesMonitorSuite) TestMultipleHashes_Failure() {
   224  	err := s.monitor.Add(testIDs, []types.Hash{{0x01}, {0x02}}, []*types.NewMessage{{}})
   225  	s.Require().Error(err)
   226  }
   227  
   228  func (s *EnvelopesMonitorSuite) TestRetryOnce() {
   229  	s.monitor.api = &mockWakuAPI{}
   230  	err := s.monitor.Add(testIDs, testHashes, []*types.NewMessage{{}})
   231  	s.Require().NoError(err)
   232  	envelope := s.monitor.envelopes[testHash]
   233  	envelope.attempts = 2
   234  	envelope.lastAttemptTime = time.Now().Add(-20 * time.Second)
   235  	s.monitor.retryQueue = append(s.monitor.retryQueue, envelope)
   236  
   237  	s.monitor.retryOnce()
   238  
   239  	s.Require().Equal(3, envelope.attempts)
   240  	s.Require().Len(s.monitor.retryQueue, 0)
   241  	s.Require().Equal(envelope.envelopeHashID, s.monitor.envelopes[envelope.envelopeHashID].envelopeHashID)
   242  }
   243  
   244  type mockWakuAPI struct{}
   245  
   246  func (m *mockWakuAPI) Post(ctx context.Context, msg types.NewMessage) ([]byte, error) {
   247  	return []byte{0x01}, nil
   248  }
   249  
   250  func (m *mockWakuAPI) AddPrivateKey(ctx context.Context, privateKey types.HexBytes) (string, error) {
   251  	return "", nil
   252  }
   253  func (m *mockWakuAPI) GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error) {
   254  	return "", nil
   255  }
   256  func (m *mockWakuAPI) DeleteKeyPair(ctx context.Context, key string) (bool, error) {
   257  	return false, nil
   258  }
   259  func (m *mockWakuAPI) NewMessageFilter(req types.Criteria) (string, error) {
   260  	return "", nil
   261  }
   262  func (m *mockWakuAPI) GetFilterMessages(id string) ([]*types.Message, error) {
   263  	return nil, nil
   264  }
   265  func (m *mockWakuAPI) BloomFilter() []byte {
   266  	return nil
   267  }