• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 13211764208

08 Feb 2025 03:08AM UTC coverage: 49.288% (-9.5%) from 58.815%
13211764208

Pull #9489

github

calvinrzachman
itest: verify switchrpc server enforces send then track

We prevent the rpc server from allowing onion dispatches for
attempt IDs which have already been tracked by rpc clients.

This helps protect the client from leaking a duplicate onion
attempt. NOTE: This is not the only method for solving this
issue! The issue could be addressed via careful client side
programming which accounts for the uncertainty and async
nature of dispatching onions to a remote process via RPC.
This would require some lnd ChannelRouter changes for how
we intend to use these RPCs though.
Pull Request #9489: multi: add BuildOnion, SendOnion, and TrackOnion RPCs

474 of 990 new or added lines in 11 files covered. (47.88%)

27321 existing lines in 435 files now uncovered.

101192 of 205306 relevant lines covered (49.29%)

1.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.67
/watchtower/wtdb/tower.go
1
package wtdb
2

3
import (
4
        "encoding/hex"
5
        "fmt"
6
        "io"
7
        "net"
8

9
        "github.com/btcsuite/btcd/btcec/v2"
10
        "github.com/lightningnetwork/lnd/tlv"
11
)
12

13
// TowerStatus represents the state of the tower as set by the tower client.
14
type TowerStatus uint8
15

16
const (
17
        // TowerStatusActive is the default state of the tower, and it indicates
18
        // that this tower should be used to attempt session creation.
19
        TowerStatusActive TowerStatus = 0
20

21
        // TowerStatusInactive indicates that the tower should not be used to
22
        // attempt session creation.
23
        TowerStatusInactive TowerStatus = 1
24
)
25

26
const (
27
        // TowerStatusTLVType is the TLV type number that will be used to store
28
        // the tower's status.
29
        TowerStatusTLVType = tlv.Type(0)
30
)
31

32
// TowerID is a unique 64-bit identifier allocated to each unique watchtower.
33
// This allows the client to conserve on-disk space by not needing to always
34
// reference towers by their pubkey.
35
type TowerID uint64
36

37
// TowerIDFromBytes constructs a TowerID from the provided byte slice. The
38
// argument must have at least 8 bytes, and should contain the TowerID in
39
// big-endian byte order.
40
func TowerIDFromBytes(towerIDBytes []byte) TowerID {
3✔
41
        return TowerID(byteOrder.Uint64(towerIDBytes))
3✔
42
}
3✔
43

44
// Bytes encodes a TowerID into an 8-byte slice in big-endian byte order.
45
func (id TowerID) Bytes() []byte {
3✔
46
        var buf [8]byte
3✔
47
        byteOrder.PutUint64(buf[:], uint64(id))
3✔
48
        return buf[:]
3✔
49
}
3✔
50

51
// Tower holds the necessary components required to connect to a remote tower.
52
// Communication is handled by brontide, and requires both a public key and an
53
// address.
54
type Tower struct {
55
        // ID is a unique ID for this record assigned by the database.
56
        ID TowerID
57

58
        // IdentityKey is the public key of the remote node, used to
59
        // authenticate the brontide transport.
60
        IdentityKey *btcec.PublicKey
61

62
        // Addresses is a list of possible addresses to reach the tower.
63
        Addresses []net.Addr
64

65
        // Status is the status of this tower as set by the client.
66
        Status TowerStatus
67
}
68

69
// AddAddress adds the given address to the tower's in-memory list of addresses.
70
// If the address's string is already present, the Tower will be left
71
// unmodified. Otherwise, the address is prepended to the beginning of the
72
// Tower's addresses, on the assumption that it is fresher than the others.
73
//
74
// NOTE: This method is NOT safe for concurrent use.
75
func (t *Tower) AddAddress(addr net.Addr) {
3✔
76
        // Ensure we don't add a duplicate address.
3✔
77
        addrStr := addr.String()
3✔
78
        for _, existingAddr := range t.Addresses {
6✔
79
                if existingAddr.String() == addrStr {
6✔
80
                        return
3✔
81
                }
3✔
82
        }
83

84
        // Add this address to the front of the list, on the assumption that it
85
        // is a fresher address and will be tried first.
UNCOV
86
        t.Addresses = append([]net.Addr{addr}, t.Addresses...)
×
87
}
88

89
// RemoveAddress removes the given address from the tower's in-memory list of
90
// addresses. If the address doesn't exist, then this will act as a NOP.
UNCOV
91
func (t *Tower) RemoveAddress(addr net.Addr) {
×
UNCOV
92
        addrStr := addr.String()
×
UNCOV
93
        for i, address := range t.Addresses {
×
UNCOV
94
                if address.String() != addrStr {
×
UNCOV
95
                        continue
×
96
                }
UNCOV
97
                t.Addresses = append(t.Addresses[:i], t.Addresses[i+1:]...)
×
UNCOV
98
                return
×
99
        }
100
}
101

102
// String returns a user-friendly identifier of the tower.
103
func (t *Tower) String() string {
×
104
        pubKey := hex.EncodeToString(t.IdentityKey.SerializeCompressed())
×
105
        if len(t.Addresses) == 0 {
×
106
                return pubKey
×
107
        }
×
108
        return fmt.Sprintf("%v@%v", pubKey, t.Addresses[0])
×
109
}
110

111
// Encode writes the Tower to the passed io.Writer. The TowerID is not
112
// serialized, since it acts as the key.
113
func (t *Tower) Encode(w io.Writer) error {
3✔
114
        err := WriteElements(w,
3✔
115
                t.IdentityKey,
3✔
116
                t.Addresses,
3✔
117
        )
3✔
118
        if err != nil {
3✔
119
                return err
×
120
        }
×
121

122
        status := uint8(t.Status)
3✔
123
        tlvRecords := []tlv.Record{
3✔
124
                tlv.MakePrimitiveRecord(TowerStatusTLVType, &status),
3✔
125
        }
3✔
126

3✔
127
        tlvStream, err := tlv.NewStream(tlvRecords...)
3✔
128
        if err != nil {
3✔
129
                return err
×
130
        }
×
131

132
        return tlvStream.Encode(w)
3✔
133
}
134

135
// Decode reads a Tower from the passed io.Reader. The TowerID is meant to be
136
// decoded from the key.
137
func (t *Tower) Decode(r io.Reader) error {
3✔
138
        err := ReadElements(r,
3✔
139
                &t.IdentityKey,
3✔
140
                &t.Addresses,
3✔
141
        )
3✔
142
        if err != nil {
3✔
143
                return err
×
144
        }
×
145

146
        var status uint8
3✔
147
        tlvRecords := []tlv.Record{
3✔
148
                tlv.MakePrimitiveRecord(TowerStatusTLVType, &status),
3✔
149
        }
3✔
150

3✔
151
        tlvStream, err := tlv.NewStream(tlvRecords...)
3✔
152
        if err != nil {
3✔
153
                return err
×
154
        }
×
155

156
        typeMap, err := tlvStream.DecodeWithParsedTypes(r)
3✔
157
        if err != nil {
3✔
158
                return err
×
159
        }
×
160

161
        if _, ok := typeMap[TowerStatusTLVType]; ok {
6✔
162
                t.Status = TowerStatus(status)
3✔
163
        }
3✔
164

165
        return nil
3✔
166
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc