github.com/decred/dcrlnd@v0.7.6/discovery/gossiper_state.go (about) 1 package discovery 2 3 import ( 4 "errors" 5 "time" 6 7 "github.com/decred/dcrlnd/channeldb" 8 "github.com/decred/dcrlnd/routing/route" 9 ) 10 11 // GossiperState is an interface that defines the functions necessary to persist 12 // gossip data about a peer. 13 type GossiperState interface { 14 // UpdatePeerLastGossipMsgTS stores the specified timestamp as the 15 // timestamp of the most recent gossip message received from the 16 // specified peer. If this timestamp is older than a previously stored 17 // timestamp, this function returns false and a nil error. 18 UpdatePeerLastGossipMsgTS(peer route.Vertex, ts time.Time) (bool, error) 19 20 // ReadPeerLastGossipMsgTS returns the timestamp stored as most recent 21 // for a gossip message received from the specified peer. 22 ReadPeerLastGossipMsgTS(peer route.Vertex) (time.Time, error) 23 } 24 25 // gossiperStateDB fulfills the GossiperState interface by using a backing 26 // channeldb.DB instance. 27 type gossiperStateDB struct { 28 db *channeldb.DB 29 } 30 31 // NewGossiperState initializes a new GossiperState using the specified channel 32 // database for persistent storage. 33 func NewGossiperState(db *channeldb.DB) GossiperState { 34 return &gossiperStateDB{db: db} 35 } 36 37 // UpdatePeerLastGossipMsgTS stores the specified timestamp as the 38 // timestamp of the most recent gossip message received from the 39 // specified peer. If this timestamp is older than a previously stored 40 // timestamp, this function returns an error. 41 func (gs *gossiperStateDB) UpdatePeerLastGossipMsgTS(peer route.Vertex, ts time.Time) (bool, error) { 42 err := gs.db.UpdatePeerLastGossipMsgTS(peer, ts) 43 if errors.Is(err, channeldb.ErrOutdatedLastGossipMsgTS) { 44 // We mute this error, because it could happen due to the 45 // ordering of processing the messages and it doesn't affect 46 // future queries. 47 log.Tracef("GossipSyncer(%s): Outdated ts %s", 48 peer, ts) 49 return false, nil 50 } 51 return err == nil, err 52 } 53 54 // ReadPeerLastGossipMsgTS returns the timestamp stored as most recent 55 // for a gossip message received from the specified peer. 56 func (gs *gossiperStateDB) ReadPeerLastGossipMsgTS(peer route.Vertex) (time.Time, error) { 57 return gs.db.ReadPeerLastGossipMsgTS(peer) 58 } 59 60 // updateGossiperMsgTS is called after processing a remote gossip message to 61 // persist the state of the gossip syncer. 62 func (d *AuthenticatedGossiper) updateGossiperMsgTS(peer route.Vertex, ts time.Time) { 63 syncer, ok := d.syncMgr.GossipSyncer(peer) 64 if !ok { 65 log.Warnf("Gossip syncer for peer=%s not found", 66 peer) 67 return 68 } 69 70 // Ignore updates when the timestamp is in the future, to avoid missing 71 // future updates when someone announced with an incorrect timestamp. 72 if ts.After(time.Now()) { 73 log.Tracef("GossipSyncer(%s): ignoring update to future ts %s", 74 peer, ts) 75 return 76 } 77 78 // Only update the stored last sync time if we're in active sync mode. 79 // Storing at other times could cause us to store a timestamp received 80 // from a historical search. 81 if syncer.syncState() != chansSynced || syncer.SyncType() != ActiveSync { 82 log.Tracef("GossipSyncer(%s): ignoring update to ts %s", 83 peer, ts) 84 return 85 } 86 87 updated, err := d.cfg.GossiperState.UpdatePeerLastGossipMsgTS(peer, ts) 88 if err != nil { 89 log.Warnf("GossipSyncer(%s): Unable to update last gossip msg ts: %v", 90 peer, err) 91 return 92 } 93 94 if updated { 95 log.Debugf("GossipSyncer(%s): Updated last gossip msg ts to %s", 96 peer, ts) 97 } 98 } 99 100 // initialGossipTimestamp returns the initial timestamp to use for the next 101 // gossip timestamp range message. This is either the timestamp for the last 102 // message we received from this syncer or the current time (if we never synced 103 // to this peer before). 104 func (g *GossipSyncer) initialGossipTimestamp() time.Time { 105 ts, err := g.cfg.gossiperState.ReadPeerLastGossipMsgTS(g.cfg.peerPub) 106 if err != nil { 107 return time.Now() 108 } 109 110 // When we wrongly stored the timestamp as a date in the future, use 111 // a date in the past as initial gossip timestamp. This prevents some 112 // classes of bugs where we never receive new gossip messages because 113 // we stored a timestamp in the future. 114 now := time.Now() 115 if ts.After(now) { 116 ts = now.Add(-time.Hour * 24) 117 } 118 119 return ts 120 }