package channeldb import ( "bytes" "errors" "fmt" "time" "github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/routing/route" ) var ( // peersBucket is the name of a top level bucket in which we store // information about our peers. Information for different peers is // stored in buckets keyed by their public key. // // // peers-bucket // | // |-- // | |--flap-count-key: // | // |-- // | |--flap-count-key: peersBucket = []byte("peers-bucket") // flapCountKey is a key used in the peer pubkey sub-bucket that stores // the timestamp of a peer's last flap count and its all time flap // count. flapCountKey = []byte("flap-count") ) var ( // ErrNoPeerBucket is returned when we try to read entries for a peer // that is not tracked. ErrNoPeerBucket = errors.New("peer bucket not found") ) // FlapCount contains information about a peer's flap count. type FlapCount struct { // Count provides the total flap count for a peer. Count uint32 // LastFlap is the timestamp of the last flap recorded for a peer. LastFlap time.Time } // WriteFlapCounts writes the flap count for a set of peers to disk, creating a // bucket for the peer's pubkey if necessary. Note that this function overwrites // the current value. func (d *DB) WriteFlapCounts(flapCounts map[route.Vertex]*FlapCount) error { return kvdb.Update(d, func(tx kvdb.RwTx) error { // Run through our set of flap counts and record them for // each peer, creating a bucket for the peer pubkey if required. for peer, flapCount := range flapCounts { peers := tx.ReadWriteBucket(peersBucket) peerBucket, err := peers.CreateBucketIfNotExists( peer[:], ) if err != nil { return err } var b bytes.Buffer err = serializeTime(&b, flapCount.LastFlap) if err != nil { return err } if err = WriteElement(&b, flapCount.Count); err != nil { return err } err = peerBucket.Put(flapCountKey, b.Bytes()) if err != nil { return err } } return nil }, func() {}) } // ReadFlapCount attempts to read the flap count for a peer, failing if the // peer is not found or we do not have flap count stored. func (d *DB) ReadFlapCount(pubkey route.Vertex) (*FlapCount, error) { var flapCount FlapCount if err := kvdb.View(d, func(tx kvdb.RTx) error { peers := tx.ReadBucket(peersBucket) peerBucket := peers.NestedReadBucket(pubkey[:]) if peerBucket == nil { return ErrNoPeerBucket } flapBytes := peerBucket.Get(flapCountKey) if flapBytes == nil { return fmt.Errorf("flap count not recorded for: %v", pubkey) } var ( err error r = bytes.NewReader(flapBytes) ) flapCount.LastFlap, err = deserializeTime(r) if err != nil { return err } return ReadElements(r, &flapCount.Count) }, func() { flapCount = FlapCount{} }); err != nil { return nil, err } return &flapCount, nil }