• 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

56.25
/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.
20
func decodeBech32(bech string) (string, []byte, error) {
3✔
21
        // The maximum allowed length for a bech32 string is 90. It must also
3✔
22
        // be at least 8 characters, since it needs a non-empty HRP, a
3✔
23
        // separator, and a 6 character checksum.
3✔
24
        // NB: The 90 character check specified in BIP173 is skipped here, to
3✔
25
        // allow strings longer than 90 characters.
3✔
26
        if len(bech) < 8 {
3✔
UNCOV
27
                return "", nil, fmt.Errorf("invalid bech32 string length %d",
×
UNCOV
28
                        len(bech))
×
UNCOV
29
        }
×
30
        // Only        ASCII characters between 33 and 126 are allowed.
31
        for i := 0; i < len(bech); i++ {
6✔
32
                if bech[i] < 33 || bech[i] > 126 {
3✔
UNCOV
33
                        return "", nil, fmt.Errorf("invalid character in "+
×
UNCOV
34
                                "string: '%c'", bech[i])
×
UNCOV
35
                }
×
36
        }
37

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

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

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

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

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

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

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

86
// toBytes converts each character in the string 'chars' to the value of the
87
// index of the corresponding character in 'charset'.
88
func toBytes(chars string) ([]byte, error) {
3✔
89
        decoded := make([]byte, 0, len(chars))
3✔
90
        for i := 0; i < len(chars); i++ {
6✔
91
                index := strings.IndexByte(charset, chars[i])
3✔
92
                if index < 0 {
3✔
UNCOV
93
                        return nil, fmt.Errorf("invalid character not part of "+
×
UNCOV
94
                                "charset: %v", chars[i])
×
UNCOV
95
                }
×
96
                decoded = append(decoded, byte(index))
3✔
97
        }
98
        return decoded, nil
3✔
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'.
UNCOV
103
func toChars(data []byte) (string, error) {
×
UNCOV
104
        result := make([]byte, 0, len(data))
×
UNCOV
105
        for _, b := range data {
×
UNCOV
106
                if int(b) >= len(charset) {
×
107
                        return "", fmt.Errorf("invalid data byte: %v", b)
×
108
                }
×
UNCOV
109
                result = append(result, charset[b])
×
110
        }
UNCOV
111
        return string(result), nil
×
112
}
113

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

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

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

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