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 }