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

     1  package transport
     2  
     3  import (
     4  	"context"
     5  	"crypto/ecdsa"
     6  	"database/sql"
     7  	"encoding/hex"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/google/uuid"
    12  	"github.com/libp2p/go-libp2p/core/peer"
    13  	"github.com/multiformats/go-multiaddr"
    14  	"github.com/pkg/errors"
    15  	"go.uber.org/zap"
    16  	"golang.org/x/exp/maps"
    17  
    18  	"github.com/ethereum/go-ethereum/common"
    19  	"github.com/ethereum/go-ethereum/p2p/enode"
    20  	"github.com/status-im/status-go/connection"
    21  	"github.com/status-im/status-go/eth-node/crypto"
    22  	"github.com/status-im/status-go/eth-node/types"
    23  )
    24  
    25  var (
    26  	// ErrNoMailservers returned if there is no configured mailservers that can be used.
    27  	ErrNoMailservers = errors.New("no configured mailservers")
    28  )
    29  
    30  type transportKeysManager struct {
    31  	waku types.Waku
    32  
    33  	// Identity of the current user.
    34  	privateKey *ecdsa.PrivateKey
    35  
    36  	passToSymKeyMutex sync.RWMutex
    37  	passToSymKeyCache map[string]string
    38  }
    39  
    40  func (m *transportKeysManager) AddOrGetKeyPair(priv *ecdsa.PrivateKey) (string, error) {
    41  	// caching is handled in waku
    42  	return m.waku.AddKeyPair(priv)
    43  }
    44  
    45  func (m *transportKeysManager) AddOrGetSymKeyFromPassword(password string) (string, error) {
    46  	m.passToSymKeyMutex.Lock()
    47  	defer m.passToSymKeyMutex.Unlock()
    48  
    49  	if val, ok := m.passToSymKeyCache[password]; ok {
    50  		return val, nil
    51  	}
    52  
    53  	id, err := m.waku.AddSymKeyFromPassword(password)
    54  	if err != nil {
    55  		return id, err
    56  	}
    57  
    58  	m.passToSymKeyCache[password] = id
    59  
    60  	return id, nil
    61  }
    62  
    63  func (m *transportKeysManager) RawSymKey(id string) ([]byte, error) {
    64  	return m.waku.GetSymKey(id)
    65  }
    66  
    67  type Option func(*Transport) error
    68  
    69  // Transport is a transport based on Whisper service.
    70  type Transport struct {
    71  	waku        types.Waku
    72  	api         types.PublicWakuAPI // only PublicWakuAPI implements logic to send messages
    73  	keysManager *transportKeysManager
    74  	filters     *FiltersManager
    75  	logger      *zap.Logger
    76  	cache       *ProcessedMessageIDsCache
    77  
    78  	mailservers      []string
    79  	envelopesMonitor *EnvelopesMonitor
    80  	quit             chan struct{}
    81  }
    82  
    83  // NewTransport returns a new Transport.
    84  // TODO: leaving a chat should verify that for a given public key
    85  //
    86  //	there are no other chats. It may happen that we leave a private chat
    87  //	but still have a public chat for a given public key.
    88  func NewTransport(
    89  	waku types.Waku,
    90  	privateKey *ecdsa.PrivateKey,
    91  	db *sql.DB,
    92  	sqlitePersistenceTableName string,
    93  	mailservers []string,
    94  	envelopesMonitorConfig *EnvelopesMonitorConfig,
    95  	logger *zap.Logger,
    96  	opts ...Option,
    97  ) (*Transport, error) {
    98  	filtersManager, err := NewFiltersManager(newSQLitePersistence(db, sqlitePersistenceTableName), waku, privateKey, logger)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	var envelopesMonitor *EnvelopesMonitor
   104  	if envelopesMonitorConfig != nil {
   105  		envelopesMonitor = NewEnvelopesMonitor(waku, *envelopesMonitorConfig)
   106  		envelopesMonitor.Start()
   107  	}
   108  
   109  	var api types.PublicWhisperAPI
   110  	if waku != nil {
   111  		api = waku.PublicWakuAPI()
   112  	}
   113  	t := &Transport{
   114  		waku:             waku,
   115  		api:              api,
   116  		cache:            NewProcessedMessageIDsCache(db),
   117  		envelopesMonitor: envelopesMonitor,
   118  		quit:             make(chan struct{}),
   119  		keysManager: &transportKeysManager{
   120  			waku:              waku,
   121  			privateKey:        privateKey,
   122  			passToSymKeyCache: make(map[string]string),
   123  		},
   124  		filters:     filtersManager,
   125  		mailservers: mailservers,
   126  		logger:      logger.With(zap.Namespace("Transport")),
   127  	}
   128  
   129  	for _, opt := range opts {
   130  		if err := opt(t); err != nil {
   131  			return nil, err
   132  		}
   133  	}
   134  
   135  	t.cleanFiltersLoop()
   136  
   137  	return t, nil
   138  }
   139  
   140  func (t *Transport) InitFilters(chatIDs []FiltersToInitialize, publicKeys []*ecdsa.PublicKey) ([]*Filter, error) {
   141  	return t.filters.Init(chatIDs, publicKeys)
   142  }
   143  
   144  func (t *Transport) InitPublicFilters(filtersToInit []FiltersToInitialize) ([]*Filter, error) {
   145  	return t.filters.InitPublicFilters(filtersToInit)
   146  }
   147  
   148  func (t *Transport) Filters() []*Filter {
   149  	return t.filters.Filters()
   150  }
   151  
   152  func (t *Transport) FilterByChatID(chatID string) *Filter {
   153  	return t.filters.FilterByChatID(chatID)
   154  }
   155  
   156  func (t *Transport) FilterByTopic(topic []byte) *Filter {
   157  	return t.filters.FilterByTopic(topic)
   158  }
   159  
   160  func (t *Transport) FiltersByIdentities(identities []string) []*Filter {
   161  	return t.filters.FiltersByIdentities(identities)
   162  }
   163  
   164  func (t *Transport) LoadFilters(filters []*Filter) ([]*Filter, error) {
   165  	return t.filters.InitWithFilters(filters)
   166  }
   167  
   168  func (t *Transport) InitCommunityFilters(communityFiltersToInitialize []CommunityFilterToInitialize) ([]*Filter, error) {
   169  	return t.filters.InitCommunityFilters(communityFiltersToInitialize)
   170  }
   171  
   172  func (t *Transport) RemoveFilters(filters []*Filter) error {
   173  	return t.filters.Remove(context.Background(), filters...)
   174  }
   175  
   176  func (t *Transport) RemoveFilterByChatID(chatID string) (*Filter, error) {
   177  	return t.filters.RemoveFilterByChatID(chatID)
   178  }
   179  
   180  func (t *Transport) ResetFilters(ctx context.Context) error {
   181  	return t.filters.Reset(ctx)
   182  }
   183  
   184  func (t *Transport) ProcessNegotiatedSecret(secret types.NegotiatedSecret) (*Filter, error) {
   185  	filter, err := t.filters.LoadNegotiated(secret)
   186  	if err != nil {
   187  		return nil, err
   188  	}
   189  	return filter, nil
   190  }
   191  
   192  func (t *Transport) JoinPublic(chatID string) (*Filter, error) {
   193  	return t.filters.LoadPublic(chatID, "")
   194  }
   195  
   196  func (t *Transport) LeavePublic(chatID string) error {
   197  	chat := t.filters.Filter(chatID)
   198  	if chat != nil {
   199  		return nil
   200  	}
   201  	return t.filters.Remove(context.Background(), chat)
   202  }
   203  
   204  func (t *Transport) JoinPrivate(publicKey *ecdsa.PublicKey) (*Filter, error) {
   205  	return t.filters.LoadContactCode(publicKey)
   206  }
   207  
   208  func (t *Transport) JoinGroup(publicKeys []*ecdsa.PublicKey) ([]*Filter, error) {
   209  	var filters []*Filter
   210  	for _, pk := range publicKeys {
   211  		f, err := t.filters.LoadContactCode(pk)
   212  		if err != nil {
   213  			return nil, err
   214  		}
   215  		filters = append(filters, f)
   216  
   217  	}
   218  	return filters, nil
   219  }
   220  
   221  func (t *Transport) GetStats() types.StatsSummary {
   222  	return t.waku.GetStats()
   223  }
   224  
   225  func (t *Transport) RetrieveRawAll() (map[Filter][]*types.Message, error) {
   226  	result := make(map[Filter][]*types.Message)
   227  	logger := t.logger.With(zap.String("site", "retrieveRawAll"))
   228  
   229  	for _, filter := range t.filters.Filters() {
   230  		msgs, err := t.api.GetFilterMessages(filter.FilterID)
   231  		if err != nil {
   232  			logger.Warn("failed to fetch messages", zap.Error(err))
   233  			continue
   234  		}
   235  		// Don't pull from filters we don't listen to
   236  		if !filter.Listen {
   237  			for _, msg := range msgs {
   238  				t.waku.MarkP2PMessageAsProcessed(common.BytesToHash(msg.Hash))
   239  			}
   240  			continue
   241  		}
   242  
   243  		if len(msgs) == 0 {
   244  			continue
   245  		}
   246  
   247  		ids := make([]string, len(msgs))
   248  		for i := range msgs {
   249  			id := types.EncodeHex(msgs[i].Hash)
   250  			ids[i] = id
   251  		}
   252  
   253  		hits, err := t.cache.Hits(ids)
   254  		if err != nil {
   255  			logger.Error("failed to check messages exists", zap.Error(err))
   256  			return nil, err
   257  		}
   258  
   259  		for i := range msgs {
   260  			// Exclude anything that is a cache hit
   261  			if !hits[types.EncodeHex(msgs[i].Hash)] {
   262  				result[*filter] = append(result[*filter], msgs[i])
   263  				logger.Debug("message not cached", zap.String("hash", types.EncodeHex(msgs[i].Hash)))
   264  			} else {
   265  				logger.Debug("message cached", zap.String("hash", types.EncodeHex(msgs[i].Hash)))
   266  				t.waku.MarkP2PMessageAsProcessed(common.BytesToHash(msgs[i].Hash))
   267  			}
   268  		}
   269  
   270  	}
   271  
   272  	return result, nil
   273  }
   274  
   275  // SendPublic sends a new message using the Whisper service.
   276  // For public filters, chat name is used as an ID as well as
   277  // a topic.
   278  func (t *Transport) SendPublic(ctx context.Context, newMessage *types.NewMessage, chatName string) ([]byte, error) {
   279  	if err := t.addSig(newMessage); err != nil {
   280  		return nil, err
   281  	}
   282  
   283  	filter, err := t.filters.LoadPublic(chatName, newMessage.PubsubTopic)
   284  	if err != nil {
   285  		return nil, err
   286  	}
   287  
   288  	newMessage.SymKeyID = filter.SymKeyID
   289  	newMessage.Topic = filter.ContentTopic
   290  	newMessage.PubsubTopic = filter.PubsubTopic
   291  
   292  	return t.api.Post(ctx, *newMessage)
   293  }
   294  
   295  func (t *Transport) SendPrivateWithSharedSecret(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey, secret []byte) ([]byte, error) {
   296  	if err := t.addSig(newMessage); err != nil {
   297  		return nil, err
   298  	}
   299  
   300  	filter, err := t.filters.LoadNegotiated(types.NegotiatedSecret{
   301  		PublicKey: publicKey,
   302  		Key:       secret,
   303  	})
   304  	if err != nil {
   305  		return nil, err
   306  	}
   307  
   308  	newMessage.SymKeyID = filter.SymKeyID
   309  	newMessage.Topic = filter.ContentTopic
   310  	newMessage.PubsubTopic = filter.PubsubTopic
   311  	newMessage.PublicKey = nil
   312  
   313  	return t.api.Post(ctx, *newMessage)
   314  }
   315  
   316  func (t *Transport) SendPrivateWithPartitioned(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) {
   317  	if err := t.addSig(newMessage); err != nil {
   318  		return nil, err
   319  	}
   320  
   321  	filter, err := t.filters.LoadPartitioned(publicKey, t.keysManager.privateKey, false)
   322  	if err != nil {
   323  		return nil, err
   324  	}
   325  
   326  	newMessage.PubsubTopic = filter.PubsubTopic
   327  	newMessage.Topic = filter.ContentTopic
   328  	newMessage.PublicKey = crypto.FromECDSAPub(publicKey)
   329  
   330  	return t.api.Post(ctx, *newMessage)
   331  }
   332  
   333  func (t *Transport) SendPrivateOnPersonalTopic(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) {
   334  	if err := t.addSig(newMessage); err != nil {
   335  		return nil, err
   336  	}
   337  
   338  	filter, err := t.filters.LoadPersonal(publicKey, t.keysManager.privateKey, false)
   339  	if err != nil {
   340  		return nil, err
   341  	}
   342  
   343  	newMessage.PubsubTopic = filter.PubsubTopic
   344  	newMessage.Topic = filter.ContentTopic
   345  	newMessage.PublicKey = crypto.FromECDSAPub(publicKey)
   346  
   347  	return t.api.Post(ctx, *newMessage)
   348  }
   349  
   350  func (t *Transport) PersonalTopicFilter() *Filter {
   351  	return t.filters.PersonalTopicFilter()
   352  }
   353  
   354  func (t *Transport) LoadKeyFilters(key *ecdsa.PrivateKey) (*Filter, error) {
   355  	return t.filters.LoadEphemeral(&key.PublicKey, key, true)
   356  }
   357  
   358  func (t *Transport) SendCommunityMessage(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) {
   359  	if err := t.addSig(newMessage); err != nil {
   360  		return nil, err
   361  	}
   362  
   363  	// We load the filter to make sure we can post on it
   364  	filter, err := t.filters.LoadPublic(PubkeyToHex(publicKey)[2:], newMessage.PubsubTopic)
   365  	if err != nil {
   366  		return nil, err
   367  	}
   368  
   369  	newMessage.PubsubTopic = filter.PubsubTopic
   370  	newMessage.Topic = filter.ContentTopic
   371  	newMessage.PublicKey = crypto.FromECDSAPub(publicKey)
   372  
   373  	return t.api.Post(ctx, *newMessage)
   374  }
   375  
   376  func (t *Transport) cleanFilters() error {
   377  	return t.filters.RemoveNoListenFilters()
   378  }
   379  
   380  func (t *Transport) addSig(newMessage *types.NewMessage) error {
   381  	sigID, err := t.keysManager.AddOrGetKeyPair(t.keysManager.privateKey)
   382  	if err != nil {
   383  		return err
   384  	}
   385  	newMessage.SigID = sigID
   386  	return nil
   387  }
   388  
   389  func (t *Transport) Track(identifier []byte, hashes [][]byte, newMessages []*types.NewMessage) {
   390  	t.TrackMany([][]byte{identifier}, hashes, newMessages)
   391  }
   392  
   393  func (t *Transport) TrackMany(identifiers [][]byte, hashes [][]byte, newMessages []*types.NewMessage) {
   394  	if t.envelopesMonitor == nil {
   395  		return
   396  	}
   397  
   398  	envelopeHashes := make([]types.Hash, len(hashes))
   399  	for i, hash := range hashes {
   400  		envelopeHashes[i] = types.BytesToHash(hash)
   401  	}
   402  
   403  	err := t.envelopesMonitor.Add(identifiers, envelopeHashes, newMessages)
   404  	if err != nil {
   405  		t.logger.Error("failed to track messages", zap.Error(err))
   406  	}
   407  }
   408  
   409  // GetCurrentTime returns the current unix timestamp in milliseconds
   410  func (t *Transport) GetCurrentTime() uint64 {
   411  	return uint64(t.waku.GetCurrentTime().UnixNano() / int64(time.Millisecond))
   412  }
   413  
   414  func (t *Transport) MaxMessageSize() uint32 {
   415  	return t.waku.MaxMessageSize()
   416  }
   417  
   418  func (t *Transport) Stop() error {
   419  	close(t.quit)
   420  	if t.envelopesMonitor != nil {
   421  		t.envelopesMonitor.Stop()
   422  	}
   423  	return nil
   424  }
   425  
   426  // cleanFiltersLoop cleans up the topic we create for the only purpose
   427  // of sending messages.
   428  // Whenever we send a message we also need to listen to that particular topic
   429  // but in case of asymettric topics, we are not interested in listening to them.
   430  // We therefore periodically clean them up so we don't receive unnecessary data.
   431  
   432  func (t *Transport) cleanFiltersLoop() {
   433  
   434  	ticker := time.NewTicker(5 * time.Minute)
   435  	go func() {
   436  		for {
   437  			select {
   438  			case <-t.quit:
   439  				ticker.Stop()
   440  				return
   441  			case <-ticker.C:
   442  				err := t.cleanFilters()
   443  				if err != nil {
   444  					t.logger.Error("failed to clean up topics", zap.Error(err))
   445  				}
   446  			}
   447  		}
   448  	}()
   449  }
   450  
   451  func (t *Transport) WakuVersion() uint {
   452  	return t.waku.Version()
   453  }
   454  
   455  func (t *Transport) PeerCount() int {
   456  	return t.waku.PeerCount()
   457  }
   458  
   459  func (t *Transport) Peers() types.PeerStats {
   460  	return t.waku.Peers()
   461  }
   462  
   463  func (t *Transport) createMessagesRequest(
   464  	ctx context.Context,
   465  	peerID peer.ID,
   466  	from, to uint32,
   467  	previousStoreCursor types.StoreRequestCursor,
   468  	pubsubTopic string,
   469  	contentTopics []types.TopicType,
   470  	limit uint32,
   471  	waitForResponse bool,
   472  	processEnvelopes bool,
   473  ) (storeCursor types.StoreRequestCursor, envelopesCount int, err error) {
   474  	r := createMessagesRequest(from, to, nil, previousStoreCursor, pubsubTopic, contentTopics, limit)
   475  
   476  	if waitForResponse {
   477  		resultCh := make(chan struct {
   478  			storeCursor    types.StoreRequestCursor
   479  			envelopesCount int
   480  			err            error
   481  		})
   482  
   483  		go func() {
   484  			storeCursor, envelopesCount, err = t.waku.RequestStoreMessages(ctx, peerID, r, processEnvelopes)
   485  			resultCh <- struct {
   486  				storeCursor    types.StoreRequestCursor
   487  				envelopesCount int
   488  				err            error
   489  			}{storeCursor, envelopesCount, err}
   490  		}()
   491  
   492  		select {
   493  		case result := <-resultCh:
   494  			return result.storeCursor, result.envelopesCount, result.err
   495  		case <-ctx.Done():
   496  			return nil, 0, ctx.Err()
   497  		}
   498  	} else {
   499  		go func() {
   500  			_, _, err = t.waku.RequestStoreMessages(ctx, peerID, r, false)
   501  			if err != nil {
   502  				t.logger.Error("failed to request store messages", zap.Error(err))
   503  			}
   504  		}()
   505  	}
   506  
   507  	return
   508  }
   509  
   510  func (t *Transport) SendMessagesRequestForTopics(
   511  	ctx context.Context,
   512  	peerID peer.ID,
   513  	from, to uint32,
   514  	prevCursor types.StoreRequestCursor,
   515  	pubsubTopic string,
   516  	contentTopics []types.TopicType,
   517  	limit uint32,
   518  	waitForResponse bool,
   519  	processEnvelopes bool,
   520  ) (cursor types.StoreRequestCursor, envelopesCount int, err error) {
   521  	return t.createMessagesRequest(ctx, peerID, from, to, prevCursor, pubsubTopic, contentTopics, limit, waitForResponse, processEnvelopes)
   522  }
   523  
   524  func createMessagesRequest(from, to uint32, cursor []byte, storeCursor types.StoreRequestCursor, pubsubTopic string, topics []types.TopicType, limit uint32) types.MessagesRequest {
   525  	aUUID := uuid.New()
   526  	// uuid is 16 bytes, converted to hex it's 32 bytes as expected by types.MessagesRequest
   527  	id := []byte(hex.EncodeToString(aUUID[:]))
   528  	var topicBytes [][]byte
   529  	for idx := range topics {
   530  		topicBytes = append(topicBytes, topics[idx][:])
   531  	}
   532  	return types.MessagesRequest{
   533  		ID:            id,
   534  		From:          from,
   535  		To:            to,
   536  		Limit:         limit,
   537  		Cursor:        cursor,
   538  		PubsubTopic:   pubsubTopic,
   539  		ContentTopics: topicBytes,
   540  		StoreCursor:   storeCursor,
   541  	}
   542  }
   543  
   544  // ConfirmMessagesProcessed marks the messages as processed in the cache so
   545  // they won't be passed to the next layer anymore
   546  func (t *Transport) ConfirmMessagesProcessed(ids []string, timestamp uint64) error {
   547  	t.logger.Debug("confirming message processed", zap.Any("ids", ids), zap.Any("timestamp", timestamp))
   548  	return t.cache.Add(ids, timestamp)
   549  }
   550  
   551  // CleanMessagesProcessed clears the messages that are older than timestamp
   552  func (t *Transport) CleanMessagesProcessed(timestamp uint64) error {
   553  	return t.cache.Clean(timestamp)
   554  }
   555  
   556  func (t *Transport) SetEnvelopeEventsHandler(handler EnvelopeEventsHandler) error {
   557  	if t.envelopesMonitor == nil {
   558  		return errors.New("Current transport has no envelopes monitor")
   559  	}
   560  	t.envelopesMonitor.handler = handler
   561  	return nil
   562  }
   563  
   564  func (t *Transport) ClearProcessedMessageIDsCache() error {
   565  	t.logger.Debug("clearing processed messages cache")
   566  	t.waku.ClearEnvelopesCache()
   567  	return t.cache.Clear()
   568  }
   569  
   570  func (t *Transport) BloomFilter() []byte {
   571  	return t.api.BloomFilter()
   572  }
   573  
   574  func PubkeyToHex(key *ecdsa.PublicKey) string {
   575  	return types.EncodeHex(crypto.FromECDSAPub(key))
   576  }
   577  
   578  func (t *Transport) StartDiscV5() error {
   579  	return t.waku.StartDiscV5()
   580  }
   581  
   582  func (t *Transport) StopDiscV5() error {
   583  	return t.waku.StopDiscV5()
   584  }
   585  
   586  func (t *Transport) ListenAddresses() ([]multiaddr.Multiaddr, error) {
   587  	return t.waku.ListenAddresses()
   588  }
   589  
   590  func (t *Transport) RelayPeersByTopic(topic string) (*types.PeerList, error) {
   591  	return t.waku.RelayPeersByTopic(topic)
   592  }
   593  
   594  func (t *Transport) ENR() (*enode.Node, error) {
   595  	return t.waku.ENR()
   596  }
   597  
   598  func (t *Transport) AddStorePeer(address multiaddr.Multiaddr) (peer.ID, error) {
   599  	return t.waku.AddStorePeer(address)
   600  }
   601  
   602  func (t *Transport) AddRelayPeer(address multiaddr.Multiaddr) (peer.ID, error) {
   603  	return t.waku.AddRelayPeer(address)
   604  }
   605  
   606  func (t *Transport) DialPeer(address multiaddr.Multiaddr) error {
   607  	return t.waku.DialPeer(address)
   608  }
   609  
   610  func (t *Transport) DialPeerByID(peerID peer.ID) error {
   611  	return t.waku.DialPeerByID(peerID)
   612  }
   613  
   614  func (t *Transport) DropPeer(peerID peer.ID) error {
   615  	return t.waku.DropPeer(peerID)
   616  }
   617  
   618  func (t *Transport) ProcessingP2PMessages() bool {
   619  	return t.waku.ProcessingP2PMessages()
   620  }
   621  
   622  func (t *Transport) MarkP2PMessageAsProcessed(hash common.Hash) {
   623  	t.waku.MarkP2PMessageAsProcessed(hash)
   624  }
   625  
   626  func (t *Transport) SubscribeToConnStatusChanges() (*types.ConnStatusSubscription, error) {
   627  	return t.waku.SubscribeToConnStatusChanges()
   628  }
   629  
   630  func (t *Transport) ConnectionChanged(state connection.State) {
   631  	t.waku.ConnectionChanged(state)
   632  }
   633  
   634  func (t *Transport) PingPeer(ctx context.Context, peerID peer.ID) (time.Duration, error) {
   635  	return t.waku.PingPeer(ctx, peerID)
   636  }
   637  
   638  // Subscribe to a pubsub topic, passing an optional public key if the pubsub topic is protected
   639  func (t *Transport) SubscribeToPubsubTopic(topic string, optPublicKey *ecdsa.PublicKey) error {
   640  	if t.waku.Version() == 2 {
   641  		return t.waku.SubscribeToPubsubTopic(topic, optPublicKey)
   642  	}
   643  	return nil
   644  }
   645  
   646  // Unsubscribe from a pubsub topic
   647  func (t *Transport) UnsubscribeFromPubsubTopic(topic string) error {
   648  	if t.waku.Version() == 2 {
   649  		return t.waku.UnsubscribeFromPubsubTopic(topic)
   650  	}
   651  	return nil
   652  }
   653  
   654  func (t *Transport) StorePubsubTopicKey(topic string, privKey *ecdsa.PrivateKey) error {
   655  	return t.waku.StorePubsubTopicKey(topic, privKey)
   656  }
   657  
   658  func (t *Transport) RetrievePubsubTopicKey(topic string) (*ecdsa.PrivateKey, error) {
   659  	return t.waku.RetrievePubsubTopicKey(topic)
   660  }
   661  
   662  func (t *Transport) RemovePubsubTopicKey(topic string) error {
   663  	if t.waku.Version() == 2 {
   664  		return t.waku.RemovePubsubTopicKey(topic)
   665  	}
   666  	return nil
   667  }
   668  
   669  func (t *Transport) ConfirmMessageDelivered(messageID string) {
   670  	if t.envelopesMonitor == nil {
   671  		return
   672  	}
   673  	hashes, ok := t.envelopesMonitor.messageEnvelopeHashes[messageID]
   674  	if !ok {
   675  		return
   676  	}
   677  	commHashes := make([]common.Hash, len(hashes))
   678  	for i, h := range hashes {
   679  		commHashes[i] = common.BytesToHash(h[:])
   680  	}
   681  	t.waku.ConfirmMessageDelivered(commHashes)
   682  }
   683  
   684  func (t *Transport) SetStorePeerID(peerID peer.ID) {
   685  	t.waku.SetStorePeerID(peerID)
   686  }
   687  
   688  func (t *Transport) SetCriteriaForMissingMessageVerification(peerID peer.ID, filters []*Filter) {
   689  	if t.waku.Version() != 2 {
   690  		return
   691  	}
   692  
   693  	topicMap := make(map[string]map[types.TopicType]struct{})
   694  	for _, f := range filters {
   695  		if !f.Listen || f.Ephemeral {
   696  			continue
   697  		}
   698  
   699  		_, ok := topicMap[f.PubsubTopic]
   700  		if !ok {
   701  			topicMap[f.PubsubTopic] = make(map[types.TopicType]struct{})
   702  		}
   703  
   704  		topicMap[f.PubsubTopic][f.ContentTopic] = struct{}{}
   705  	}
   706  
   707  	for pubsubTopic, contentTopics := range topicMap {
   708  		ctList := maps.Keys(contentTopics)
   709  		err := t.waku.SetCriteriaForMissingMessageVerification(peerID, pubsubTopic, ctList)
   710  		if err != nil {
   711  			t.logger.Error("could not check for missing messages",
   712  				zap.Error(err),
   713  				zap.Stringer("peerID", peerID),
   714  				zap.String("pubsubTopic", pubsubTopic),
   715  				zap.Stringers("contentTopics", ctList))
   716  			return
   717  		}
   718  	}
   719  }