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

lightningnetwork / lnd / 26282430397

22 May 2026 10:26AM UTC coverage: 62.329% (+0.03%) from 62.303%
26282430397

Pull #10789

github

web-flow
Merge ee2aa98a8 into cc49b3773
Pull Request #10789: bolt12+lnwire: add codec foundation with Offer message

549 of 678 new or added lines in 12 files covered. (80.97%)

153 existing lines in 32 files now uncovered.

144272 of 231468 relevant lines covered (62.33%)

18978.73 hits per line

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

58.9
/lnwire/intro_node.go
1
package lnwire
2

3
import (
4
        "bytes"
5
        "fmt"
6
        "io"
7

8
        "github.com/btcsuite/btcd/btcec/v2"
9
)
10

11
// IntroductionNode is the sealed sum-type for a blinded path's introduction
12
// node. {0x02, 0x03} → PubkeyIntro; {0x00, 0x01} → SciddirIntro. The unexported
13
// method seals the variant set so foreign packages cannot satisfy the interface
14
// with an unrecognised wire form.
15
type IntroductionNode interface {
16
        isIntroductionNode()
17

18
        encodedLen() uint64
19

20
        encode(w io.Writer) error
21

22
        // validate checks that the discriminator byte is valid for the variant.
23
        validate() error
24

25
        // Bytes returns the wire-format encoding of the introduction node for
26
        // callers that need it outside an io.Writer (RPC surfaces).
27
        Bytes() []byte
28
}
29

30
// PubkeyIntro is the 33-byte compressed-pubkey variant. The SEC1 parity byte
31
// (0x02 or 0x03) doubles as the wire discriminator.
32
type PubkeyIntro struct {
33
        Pubkey *btcec.PublicKey
34
}
35

36
// SciddirIntro is the 9-byte sciddir variant. Direction is the wire
37
// discriminator; SCID is the 8-byte short channel ID.
38
type SciddirIntro struct {
39
        Direction byte
40
        SCID      [scidLen]byte
41
}
42

43
var (
44
        _ IntroductionNode = PubkeyIntro{}
45
        _ IntroductionNode = SciddirIntro{}
46
)
47

48
// decodeIntroductionNode reads the discriminator byte and dispatches to the
49
// matching variant.
50
func decodeIntroductionNode(r io.Reader,
51
        buf *[8]byte) (IntroductionNode, error) {
61✔
52

61✔
53
        if _, err := io.ReadFull(r, buf[:1]); err != nil {
61✔
NEW
54
                return nil, fmt.Errorf("read intro node type: %w", err)
×
NEW
55
        }
×
56

57
        disc := buf[0]
61✔
58
        switch disc {
61✔
59
        case 0x00, 0x01:
22✔
60
                s := SciddirIntro{Direction: disc}
22✔
61
                if _, err := io.ReadFull(r, s.SCID[:]); err != nil {
22✔
NEW
62
                        return nil, fmt.Errorf("read sciddir: %w", err)
×
NEW
63
                }
×
64

65
                return s, nil
22✔
66

67
        case 0x02, 0x03:
36✔
68
                var b [pubKeyLen]byte
36✔
69
                b[0] = disc
36✔
70
                if _, err := io.ReadFull(r, b[1:]); err != nil {
37✔
71
                        return nil, fmt.Errorf("read intro pubkey: %w", err)
1✔
72
                }
1✔
73
                pub, err := btcec.ParsePubKey(b[:])
35✔
74
                if err != nil {
35✔
NEW
75
                        return nil, fmt.Errorf("%w: %w",
×
NEW
76
                                ErrInvalidIntroNode, err)
×
NEW
77
                }
×
78

79
                return PubkeyIntro{Pubkey: pub}, nil
35✔
80

81
        default:
3✔
82
                return nil, fmt.Errorf("%w: 0x%02x", ErrInvalidIntroNode, disc)
3✔
83
        }
84
}
85

NEW
86
func (PubkeyIntro) isIntroductionNode() {}
×
87

88
func (p PubkeyIntro) encodedLen() uint64 { return pubKeyLen }
30✔
89

90
func (p PubkeyIntro) encode(w io.Writer) error {
33✔
91
        if p.Pubkey == nil {
33✔
NEW
92
                return fmt.Errorf("nil intro pubkey")
×
NEW
93
        }
×
94
        _, err := w.Write(p.Pubkey.SerializeCompressed())
33✔
95

33✔
96
        return err
33✔
97
}
98

99
func (p PubkeyIntro) validate() error {
38✔
100
        if p.Pubkey == nil {
39✔
101
                return fmt.Errorf("%w: nil pubkey", ErrInvalidIntroNode)
1✔
102
        }
1✔
103

104
        if !p.Pubkey.IsOnCurve() {
37✔
NEW
105
                return fmt.Errorf("%w: pubkey not on curve",
×
NEW
106
                        ErrInvalidIntroNode)
×
NEW
107
        }
×
108

109
        return nil
37✔
110
}
111

112
// Bytes returns the wire-format encoding of the pubkey variant.
NEW
113
func (p PubkeyIntro) Bytes() []byte {
×
NEW
114
        var buf bytes.Buffer
×
NEW
115
        buf.Grow(pubKeyLen)
×
NEW
116
        _ = p.encode(&buf)
×
NEW
117

×
NEW
118
        return buf.Bytes()
×
NEW
119
}
×
120

NEW
121
func (SciddirIntro) isIntroductionNode() {}
×
122

123
func (s SciddirIntro) encodedLen() uint64 { return sciddirLen }
19✔
124

125
func (s SciddirIntro) encode(w io.Writer) error {
22✔
126
        if _, err := w.Write([]byte{s.Direction}); err != nil {
22✔
NEW
127
                return err
×
NEW
128
        }
×
129
        _, err := w.Write(s.SCID[:])
22✔
130

22✔
131
        return err
22✔
132
}
133

134
func (s SciddirIntro) validate() error {
24✔
135
        switch s.Direction {
24✔
136
        case 0x00, 0x01:
22✔
137
                return nil
22✔
138
        }
139

140
        return fmt.Errorf("%w: 0x%02x", ErrInvalidIntroNode, s.Direction)
2✔
141
}
142

143
// Bytes returns the wire-format encoding of the sciddir variant.
NEW
144
func (s SciddirIntro) Bytes() []byte {
×
NEW
145
        var buf bytes.Buffer
×
NEW
146
        buf.Grow(sciddirLen)
×
NEW
147
        _ = s.encode(&buf)
×
NEW
148

×
NEW
149
        return buf.Bytes()
×
NEW
150
}
×
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

© 2026 Coveralls, Inc