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  }