• 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

0.0
/channeldb/migration_01_to_11/zpay32/bech32.go
1
package zpay32
2

3
import (
4
        "fmt"
5
        "strings"
6
)
7

8
const charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
9

10
var gen = []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
11

12
// NOTE: This method it a slight modification of the method bech32.Decode found
13
// btcutil, allowing strings to be more than 90 characters.
14

15
// decodeBech32 decodes a bech32 encoded string, returning the human-readable
16
// part and the data part excluding the checksum.
17
// Note: the data will be base32 encoded, that is each element of the returned
18
// byte array will encode 5 bits of data. Use the ConvertBits method to convert
19
// this to 8-bit representation.
UNCOV
20
func decodeBech32(bech string) (string, []byte, error) {
×
UNCOV
21
        // The maximum allowed length for a bech32 string is 90. It must also
×
UNCOV
22
        // be at least 8 characters, since it needs a non-empty HRP, a
×
UNCOV
23
        // separator, and a 6 character checksum.
×
UNCOV
24
        // NB: The 90 character check specified in BIP173 is skipped here, to
×
UNCOV
25
        // allow strings longer than 90 characters.
×
UNCOV
26
        if len(bech) < 8 {
×
27
                return "", nil, fmt.Errorf("invalid bech32 string length %d",
×
28
                        len(bech))
×
29
        }
×
30
        // Only        ASCII characters between 33 and 126 are allowed.
UNCOV
31
        for i := 0; i < len(bech); i++ {
×
UNCOV
32
                if bech[i] < 33 || bech[i] > 126 {
×
33
                        return "", nil, fmt.Errorf("invalid character in "+
×
34
                                "string: '%c'", bech[i])
×
35
                }
×
36
        }
37

38
        // The characters must be either all lowercase or all uppercase.
UNCOV
39
        lower := strings.ToLower(bech)
×
UNCOV
40
        upper := strings.ToUpper(bech)
×
UNCOV
41
        if bech != lower && bech != upper {
×
42
                return "", nil, fmt.Errorf("string not all lowercase or all " +
×
43
                        "uppercase")
×
44
        }
×
45

46
        // We'll work with the lowercase string from now on.
UNCOV
47
        bech = lower
×
UNCOV
48

×
UNCOV
49
        // The string is invalid if the last '1' is non-existent, it is the
×
UNCOV
50
        // first character of the string (no human-readable part) or one of the
×
UNCOV
51
        // last 6 characters of the string (since checksum cannot contain '1'),
×
UNCOV
52
        // or if the string is more than 90 characters in total.
×
UNCOV
53
        one := strings.LastIndexByte(bech, '1')
×
UNCOV
54
        if one < 1 || one+7 > len(bech) {
×
55
                return "", nil, fmt.Errorf("invalid index of 1")
×
56
        }
×
57

58
        // The human-readable part is everything before the last '1'.
UNCOV
59
        hrp := bech[:one]
×
UNCOV
60
        data := bech[one+1:]
×
UNCOV
61

×
UNCOV
62
        // Each character corresponds to the byte with value of the index in
×
UNCOV
63
        // 'charset'.
×
UNCOV
64
        decoded, err := toBytes(data)
×
UNCOV
65
        if err != nil {
×
66
                return "", nil, fmt.Errorf("failed converting data to bytes: "+
×
67
                        "%v", err)
×
68
        }
×
69

UNCOV
70
        if !bech32VerifyChecksum(hrp, decoded) {
×
71
                moreInfo := ""
×
72
                checksum := bech[len(bech)-6:]
×
73
                expected, err := toChars(bech32Checksum(hrp,
×
74
                        decoded[:len(decoded)-6]))
×
75
                if err == nil {
×
76
                        moreInfo = fmt.Sprintf("Expected %v, got %v.",
×
77
                                expected, checksum)
×
78
                }
×
79
                return "", nil, fmt.Errorf("checksum failed. " + moreInfo)
×
80
        }
81

82
        // We exclude the last 6 bytes, which is the checksum.
UNCOV
83
        return hrp, decoded[:len(decoded)-6], nil
×
84
}
85

86
// toBytes converts each character in the string 'chars' to the value of the
87
// index of the corresponding character in 'charset'.
UNCOV
88
func toBytes(chars string) ([]byte, error) {
×
UNCOV
89
        decoded := make([]byte, 0, len(chars))
×
UNCOV
90
        for i := 0; i < len(chars); i++ {
×
UNCOV
91
                index := strings.IndexByte(charset, chars[i])
×
UNCOV
92
                if index < 0 {
×
93
                        return nil, fmt.Errorf("invalid character not part of "+
×
94
                                "charset: %v", chars[i])
×
95
                }
×
UNCOV
96
                decoded = append(decoded, byte(index))
×
97
        }
UNCOV
98
        return decoded, nil
×
99
}
100

101
// toChars converts the byte slice 'data' to a string where each byte in 'data'
102
// encodes the index of a character in 'charset'.
103
func toChars(data []byte) (string, error) {
×
104
        result := make([]byte, 0, len(data))
×
105
        for _, b := range data {
×
106
                if int(b) >= len(charset) {
×
107
                        return "", fmt.Errorf("invalid data byte: %v", b)
×
108
                }
×
109
                result = append(result, charset[b])
×
110
        }
111
        return string(result), nil
×
112
}
113

114
// For more details on the checksum calculation, please refer to BIP 173.
115
func bech32Checksum(hrp string, data []byte) []byte {
×
116
        // Convert the bytes to list of integers, as this is needed for the
×
117
        // checksum calculation.
×
118
        integers := make([]int, len(data))
×
119
        for i, b := range data {
×
120
                integers[i] = int(b)
×
121
        }
×
122
        values := append(bech32HrpExpand(hrp), integers...)
×
123
        values = append(values, []int{0, 0, 0, 0, 0, 0}...)
×
124
        polymod := bech32Polymod(values) ^ 1
×
125
        var res []byte
×
126
        for i := 0; i < 6; i++ {
×
127
                res = append(res, byte((polymod>>uint(5*(5-i)))&31))
×
128
        }
×
129
        return res
×
130
}
131

132
// For more details on the polymod calculation, please refer to BIP 173.
UNCOV
133
func bech32Polymod(values []int) int {
×
UNCOV
134
        chk := 1
×
UNCOV
135
        for _, v := range values {
×
UNCOV
136
                b := chk >> 25
×
UNCOV
137
                chk = (chk&0x1ffffff)<<5 ^ v
×
UNCOV
138
                for i := 0; i < 5; i++ {
×
UNCOV
139
                        if (b>>uint(i))&1 == 1 {
×
UNCOV
140
                                chk ^= gen[i]
×
UNCOV
141
                        }
×
142
                }
143
        }
UNCOV
144
        return chk
×
145
}
146

147
// For more details on HRP expansion, please refer to BIP 173.
UNCOV
148
func bech32HrpExpand(hrp string) []int {
×
UNCOV
149
        v := make([]int, 0, len(hrp)*2+1)
×
UNCOV
150
        for i := 0; i < len(hrp); i++ {
×
UNCOV
151
                v = append(v, int(hrp[i]>>5))
×
UNCOV
152
        }
×
UNCOV
153
        v = append(v, 0)
×
UNCOV
154
        for i := 0; i < len(hrp); i++ {
×
UNCOV
155
                v = append(v, int(hrp[i]&31))
×
UNCOV
156
        }
×
UNCOV
157
        return v
×
158
}
159

160
// For more details on the checksum verification, please refer to BIP 173.
UNCOV
161
func bech32VerifyChecksum(hrp string, data []byte) bool {
×
UNCOV
162
        integers := make([]int, len(data))
×
UNCOV
163
        for i, b := range data {
×
UNCOV
164
                integers[i] = int(b)
×
UNCOV
165
        }
×
UNCOV
166
        concat := append(bech32HrpExpand(hrp), integers...)
×
UNCOV
167
        return bech32Polymod(concat) == 1
×
168
}
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