github.com/decred/dcrlnd@v0.7.6/discovery/message_store.go (about)

     1  package discovery
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  
     9  	"github.com/decred/dcrlnd/kvdb"
    10  	"github.com/decred/dcrlnd/lnwire"
    11  )
    12  
    13  var (
    14  	// messageStoreBucket is a key used to create a top level bucket in the
    15  	// gossiper database, used for storing messages that are to be sent to
    16  	// peers. Upon restarts, these messages will be read and resent to their
    17  	// respective peers.
    18  	//
    19  	// maps:
    20  	//   pubKey (33 bytes) + msgShortChanID (8 bytes) + msgType (2 bytes) -> msg
    21  	messageStoreBucket = []byte("message-store")
    22  
    23  	// ErrUnsupportedMessage is an error returned when we attempt to add a
    24  	// message to the store that is not supported.
    25  	ErrUnsupportedMessage = errors.New("unsupported message type")
    26  
    27  	// ErrCorruptedMessageStore indicates that the on-disk bucketing
    28  	// structure has altered since the gossip message store instance was
    29  	// initialized.
    30  	ErrCorruptedMessageStore = errors.New("gossip message store has been " +
    31  		"corrupted")
    32  )
    33  
    34  // GossipMessageStore is a store responsible for storing gossip messages which
    35  // we should reliably send to our peers.
    36  type GossipMessageStore interface {
    37  	// AddMessage adds a message to the store for this peer.
    38  	AddMessage(lnwire.Message, [33]byte) error
    39  
    40  	// DeleteMessage deletes a message from the store for this peer.
    41  	DeleteMessage(lnwire.Message, [33]byte) error
    42  
    43  	// Messages returns the total set of messages that exist within the
    44  	// store for all peers.
    45  	Messages() (map[[33]byte][]lnwire.Message, error)
    46  
    47  	// Peers returns the public key of all peers with messages within the
    48  	// store.
    49  	Peers() (map[[33]byte]struct{}, error)
    50  
    51  	// MessagesForPeer returns the set of messages that exists within the
    52  	// store for the given peer.
    53  	MessagesForPeer([33]byte) ([]lnwire.Message, error)
    54  }
    55  
    56  // MessageStore is an implementation of the GossipMessageStore interface backed
    57  // by a channeldb instance. By design, this store will only keep the latest
    58  // version of a message (like in the case of multiple ChannelUpdate's) for a
    59  // channel with a peer.
    60  type MessageStore struct {
    61  	db kvdb.Backend
    62  }
    63  
    64  // A compile-time assertion to ensure messageStore implements the
    65  // GossipMessageStore interface.
    66  var _ GossipMessageStore = (*MessageStore)(nil)
    67  
    68  // NewMessageStore creates a new message store backed by a channeldb instance.
    69  func NewMessageStore(db kvdb.Backend) (*MessageStore, error) {
    70  	err := kvdb.Batch(db, func(tx kvdb.RwTx) error {
    71  		_, err := tx.CreateTopLevelBucket(messageStoreBucket)
    72  		return err
    73  	})
    74  	if err != nil {
    75  		return nil, fmt.Errorf("unable to create required buckets: %v",
    76  			err)
    77  	}
    78  
    79  	return &MessageStore{db}, nil
    80  }
    81  
    82  // msgShortChanID retrieves the short channel ID of the message.
    83  func msgShortChanID(msg lnwire.Message) (lnwire.ShortChannelID, error) {
    84  	var shortChanID lnwire.ShortChannelID
    85  	switch msg := msg.(type) {
    86  	case *lnwire.AnnounceSignatures:
    87  		shortChanID = msg.ShortChannelID
    88  	case *lnwire.ChannelUpdate:
    89  		shortChanID = msg.ShortChannelID
    90  	default:
    91  		return shortChanID, ErrUnsupportedMessage
    92  	}
    93  
    94  	return shortChanID, nil
    95  }
    96  
    97  // messageStoreKey constructs the database key for the message to be stored.
    98  func messageStoreKey(msg lnwire.Message, peerPubKey [33]byte) ([]byte, error) {
    99  	shortChanID, err := msgShortChanID(msg)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  
   104  	var k [33 + 8 + 2]byte
   105  	copy(k[:33], peerPubKey[:])
   106  	binary.BigEndian.PutUint64(k[33:41], shortChanID.ToUint64())
   107  	binary.BigEndian.PutUint16(k[41:43], uint16(msg.MsgType()))
   108  
   109  	return k[:], nil
   110  }
   111  
   112  // AddMessage adds a message to the store for this peer.
   113  func (s *MessageStore) AddMessage(msg lnwire.Message, peerPubKey [33]byte) error {
   114  	// Construct the key for which we'll find this message with in the store.
   115  	msgKey, err := messageStoreKey(msg, peerPubKey)
   116  	if err != nil {
   117  		return err
   118  	}
   119  
   120  	// Serialize the message with its wire encoding.
   121  	var b bytes.Buffer
   122  	if _, err := lnwire.WriteMessage(&b, msg, 0); err != nil {
   123  		return err
   124  	}
   125  
   126  	return kvdb.Batch(s.db, func(tx kvdb.RwTx) error {
   127  		messageStore := tx.ReadWriteBucket(messageStoreBucket)
   128  		if messageStore == nil {
   129  			return ErrCorruptedMessageStore
   130  		}
   131  
   132  		return messageStore.Put(msgKey, b.Bytes())
   133  	})
   134  }
   135  
   136  // DeleteMessage deletes a message from the store for this peer.
   137  func (s *MessageStore) DeleteMessage(msg lnwire.Message,
   138  	peerPubKey [33]byte) error {
   139  
   140  	// Construct the key for which we'll find this message with in the
   141  	// store.
   142  	msgKey, err := messageStoreKey(msg, peerPubKey)
   143  	if err != nil {
   144  		return err
   145  	}
   146  
   147  	return kvdb.Batch(s.db, func(tx kvdb.RwTx) error {
   148  		messageStore := tx.ReadWriteBucket(messageStoreBucket)
   149  		if messageStore == nil {
   150  			return ErrCorruptedMessageStore
   151  		}
   152  
   153  		// In the event that we're attempting to delete a ChannelUpdate
   154  		// from the store, we'll make sure that we're actually deleting
   155  		// the correct one as it can be overwritten.
   156  		if msg, ok := msg.(*lnwire.ChannelUpdate); ok {
   157  			// Deleting a value from a bucket that doesn't exist
   158  			// acts as a NOP, so we'll return if a message doesn't
   159  			// exist under this key.
   160  			v := messageStore.Get(msgKey)
   161  			if v == nil {
   162  				return nil
   163  			}
   164  
   165  			dbMsg, err := lnwire.ReadMessage(bytes.NewReader(v), 0)
   166  			if err != nil {
   167  				return err
   168  			}
   169  
   170  			// If the timestamps don't match, then the update stored
   171  			// should be the latest one, so we'll avoid deleting it.
   172  			if msg.Timestamp != dbMsg.(*lnwire.ChannelUpdate).Timestamp {
   173  				return nil
   174  			}
   175  		}
   176  
   177  		return messageStore.Delete(msgKey)
   178  	})
   179  }
   180  
   181  // readMessage reads a message from its serialized form and ensures its
   182  // supported by the current version of the message store.
   183  func readMessage(msgBytes []byte) (lnwire.Message, error) {
   184  	msg, err := lnwire.ReadMessage(bytes.NewReader(msgBytes), 0)
   185  	if err != nil {
   186  		return nil, err
   187  	}
   188  
   189  	// Check if the message is supported by the store. We can reuse the
   190  	// check for ShortChannelID as its a dependency on messages stored.
   191  	if _, err := msgShortChanID(msg); err != nil {
   192  		return nil, err
   193  	}
   194  
   195  	return msg, nil
   196  }
   197  
   198  // Messages returns the total set of messages that exist within the store for
   199  // all peers.
   200  func (s *MessageStore) Messages() (map[[33]byte][]lnwire.Message, error) {
   201  	var msgs map[[33]byte][]lnwire.Message
   202  	err := kvdb.View(s.db, func(tx kvdb.RTx) error {
   203  		messageStore := tx.ReadBucket(messageStoreBucket)
   204  		if messageStore == nil {
   205  			return ErrCorruptedMessageStore
   206  		}
   207  
   208  		return messageStore.ForEach(func(k, v []byte) error {
   209  			var pubKey [33]byte
   210  			copy(pubKey[:], k[:33])
   211  
   212  			// Deserialize the message from its raw bytes and filter
   213  			// out any which are not currently supported by the
   214  			// store.
   215  			msg, err := readMessage(v)
   216  			if err == ErrUnsupportedMessage {
   217  				return nil
   218  			}
   219  			if err != nil {
   220  				return err
   221  			}
   222  
   223  			msgs[pubKey] = append(msgs[pubKey], msg)
   224  			return nil
   225  		})
   226  	}, func() {
   227  		msgs = make(map[[33]byte][]lnwire.Message)
   228  	})
   229  	if err != nil {
   230  		return nil, err
   231  	}
   232  
   233  	return msgs, nil
   234  }
   235  
   236  // MessagesForPeer returns the set of messages that exists within the store for
   237  // the given peer.
   238  func (s *MessageStore) MessagesForPeer(
   239  	peerPubKey [33]byte) ([]lnwire.Message, error) {
   240  
   241  	var msgs []lnwire.Message
   242  	err := kvdb.View(s.db, func(tx kvdb.RTx) error {
   243  		messageStore := tx.ReadBucket(messageStoreBucket)
   244  		if messageStore == nil {
   245  			return ErrCorruptedMessageStore
   246  		}
   247  
   248  		c := messageStore.ReadCursor()
   249  		k, v := c.Seek(peerPubKey[:])
   250  		for ; bytes.HasPrefix(k, peerPubKey[:]); k, v = c.Next() {
   251  			// Deserialize the message from its raw bytes and filter
   252  			// out any which are not currently supported by the
   253  			// store.
   254  			msg, err := readMessage(v)
   255  			if err == ErrUnsupportedMessage {
   256  				continue
   257  			}
   258  			if err != nil {
   259  				return err
   260  			}
   261  
   262  			msgs = append(msgs, msg)
   263  		}
   264  
   265  		return nil
   266  	}, func() {
   267  		msgs = nil
   268  	})
   269  	if err != nil {
   270  		return nil, err
   271  	}
   272  
   273  	return msgs, nil
   274  }
   275  
   276  // Peers returns the public key of all peers with messages within the store.
   277  func (s *MessageStore) Peers() (map[[33]byte]struct{}, error) {
   278  	var peers map[[33]byte]struct{}
   279  	err := kvdb.View(s.db, func(tx kvdb.RTx) error {
   280  		messageStore := tx.ReadBucket(messageStoreBucket)
   281  		if messageStore == nil {
   282  			return ErrCorruptedMessageStore
   283  		}
   284  
   285  		return messageStore.ForEach(func(k, _ []byte) error {
   286  			var pubKey [33]byte
   287  			copy(pubKey[:], k[:33])
   288  			peers[pubKey] = struct{}{}
   289  			return nil
   290  		})
   291  	}, func() {
   292  		peers = make(map[[33]byte]struct{})
   293  	})
   294  	if err != nil {
   295  		return nil, err
   296  	}
   297  
   298  	return peers, nil
   299  }