github.com/decred/dcrlnd@v0.7.6/channeldb/gossiper.go (about) 1 package channeldb 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "time" 8 9 "github.com/btcsuite/btcwallet/walletdb" 10 "github.com/decred/dcrlnd/kvdb" 11 "github.com/decred/dcrlnd/routing/route" 12 ) 13 14 var ( 15 // peerLastGossipMsgTSKey is the key for a value in the peer bucket that 16 // tracks the unix timestamp of the last received gossip message 17 // (ChannelUpdate, ChannelAnnouncement, NodeAnnounce). 18 peerLastGossipMsgTSKey = []byte("last-gossip-msg-ts") 19 20 // ErrNoPeerLastGossipMsgTS is returned when there are no recorded 21 // gossip msg timestamps for a peer. 22 ErrNoPeerLastGossipMsgTS = errors.New("last gossip msg ts not recorded") 23 24 // ErrOutdatedLastGossipMsgTS is returned when an attempt is made to 25 // store a gossip timestamp that is before the previously stored one. 26 ErrOutdatedLastGossipMsgTS = errors.New("last gossip msg ts specified " + 27 "is older than previously recorded ts") 28 ) 29 30 // readPeerLastGossipMsgTS reads and deserializes the last gossip msg timestamp 31 // for a given peer. 32 func readPeerLastGossipMsgTS(rootPeersBucket walletdb.ReadBucket, peer route.Vertex) (time.Time, error) { 33 var ts time.Time 34 35 peerBucket := rootPeersBucket.NestedReadBucket(peer[:]) 36 if peerBucket == nil { 37 return ts, fmt.Errorf("%w for peer %v", 38 ErrNoPeerLastGossipMsgTS, peer) 39 } 40 41 tsBytes := peerBucket.Get(peerLastGossipMsgTSKey) 42 if tsBytes == nil { 43 return ts, fmt.Errorf("%w for peer %v", 44 ErrNoPeerLastGossipMsgTS, peer) 45 } 46 47 r := bytes.NewReader(tsBytes) 48 return deserializeTime(r) 49 } 50 51 // UpdatePeerLastGossipMsgTS stores the specified timestamp as the timestamp of 52 // the most recent gossip message received from the specified peer. If this 53 // timestamp is older than a previously stored timestamp, this function returns 54 // an error. 55 func (d *DB) UpdatePeerLastGossipMsgTS(peer route.Vertex, ts time.Time) error { 56 return kvdb.Update(d, func(tx kvdb.RwTx) error { 57 peers := tx.ReadWriteBucket(peersBucket) 58 59 // Read existing ts. Error is ignored here, because an empty 60 // time equals 0. 61 prevTS, _ := readPeerLastGossipMsgTS(peers, peer) 62 if ts.Before(prevTS) { 63 return fmt.Errorf("%w: %s is before %s", 64 ErrOutdatedLastGossipMsgTS, ts, prevTS) 65 } 66 67 peerBucket, err := peers.CreateBucketIfNotExists( 68 peer[:], 69 ) 70 if err != nil { 71 return err 72 } 73 74 var b bytes.Buffer 75 err = serializeTime(&b, ts) 76 if err != nil { 77 return err 78 } 79 80 err = peerBucket.Put(peerLastGossipMsgTSKey, b.Bytes()) 81 if err != nil { 82 return err 83 } 84 85 return nil 86 }, func() {}) 87 } 88 89 // ReadPeerLastGossipMsgTS returns the timestamp stored as most recent for 90 // a gossip message received from the specified peer. 91 func (d *DB) ReadPeerLastGossipMsgTS(peer route.Vertex) (time.Time, error) { 92 var ts time.Time 93 err := kvdb.View(d, func(tx kvdb.RTx) error { 94 peers := tx.ReadBucket(peersBucket) 95 var err error 96 ts, err = readPeerLastGossipMsgTS(peers, peer) 97 return err 98 }, func() { ts = time.Time{} }) 99 100 return ts, err 101 }