Skip to content

Commit 771d1f0

Browse files
authored
Merge pull request #8338 from lightningnetwork/coop-close-v2-wire-messages
lnwire: add new closing_complete and closing_sig messages
2 parents 63e698e + ba3c0c4 commit 771d1f0

File tree

7 files changed

+396
-12
lines changed

7 files changed

+396
-12
lines changed

.github/CODEOWNERS

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
# respective areas
44

55
# aezeed
6-
/aezeed/ @guggero @yyforyongyu
6+
/aezeed/ @guggero @yyforyongyu @roasbeef
77

88
# alias manager
99
/aliasmgr/ @Crypt-iQ
1010

1111
# amp
12-
/amp/ @yyforyongyu
12+
/amp/ @yyforyongyu @roasbeef
1313

1414
# auto pilot
1515
/autopilot/ @bitromortac
@@ -63,7 +63,7 @@
6363
/cmd/ @ellemouton
6464

6565
# contract court
66-
/contractcourt/ @yyforyongyu
66+
/contractcourt/ @yyforyongyu @Roasbeef @Crypt-iQ
6767

6868
# contrib
6969
/contrib/ @guggero
@@ -95,11 +95,8 @@
9595
# invoices
9696
/invoices/ @yyforyongyu @bhandras
9797

98-
#itest
99-
/itest/ @yyforyongyu @ellemouton
100-
10198
# key chain
102-
/keychain/ @guggero
99+
/keychain/ @guggero @roasbeef
103100

104101
# kvdb
105102
/kvdb/ @bhandras
@@ -113,9 +110,6 @@
113110
# lnpeer
114111
/lnpeer/ @Roasbeef
115112

116-
# lnrpc
117-
/lnrpc/ @guggero @ellemouton
118-
119113
#lntest
120114
/lntest/ @yyforyongyu
121115

@@ -126,7 +120,7 @@
126120
/lnutils/ @yyforyongyu
127121

128122
# lnwallet
129-
/lnwallet/ @Roasbeef @yyforyongyu
123+
/lnwallet/ @Roasbeef @yyforyongyu @Crypt-iQ
130124

131125
# lnwire
132126
/lnwire/ @ellemouton
@@ -198,4 +192,4 @@
198192
/watchtower/ @ellemouton
199193

200194
# zpay32
201-
/zpay32/ @Roasbeef
195+
/zpay32/ @Roasbeef

lnwire/closing_complete.go

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package lnwire
2+
3+
import (
4+
"bytes"
5+
"io"
6+
7+
"github.com/btcsuite/btcd/btcutil"
8+
"github.com/lightningnetwork/lnd/tlv"
9+
)
10+
11+
// ClosingSigs houses the 3 possible signatures that can be sent when
12+
// attempting to complete a cooperative channel closure. A signature will
13+
// either include both outputs, or only one of the outputs from either side.
14+
type ClosingSigs struct {
15+
// CloserNoClosee is a signature that excludes the output of the
16+
// clsoee.
17+
CloserNoClosee tlv.OptionalRecordT[tlv.TlvType1, Sig]
18+
19+
// NoCloserClosee is a signature that excludes the output of the
20+
// closer.
21+
NoCloserClosee tlv.OptionalRecordT[tlv.TlvType2, Sig]
22+
23+
// CloserAndClosee is a signature that includes both outputs.
24+
CloserAndClosee tlv.OptionalRecordT[tlv.TlvType3, Sig]
25+
}
26+
27+
// ClosingComplete is sent by either side to kick off the process of obtaining
28+
// a valid signature on a c o-operative channel closure of their choice.
29+
type ClosingComplete struct {
30+
// ChannelID serves to identify which channel is to be closed.
31+
ChannelID ChannelID
32+
33+
// FeeSatoshis is the total fee in satoshis that the party to the
34+
// channel would like to propose for the close transaction.
35+
FeeSatoshis btcutil.Amount
36+
37+
// Sequence is the sequence number to be used in the input spending the
38+
// funding transaction.
39+
Sequence uint32
40+
41+
// ClosingSigs houses the 3 possible signatures that can be sent.
42+
ClosingSigs
43+
44+
// ExtraData is the set of data that was appended to this message to
45+
// fill out the full maximum transport message size. These fields can
46+
// be used to specify optional data such as custom TLV fields.
47+
ExtraData ExtraOpaqueData
48+
}
49+
50+
// decodeClosingSigs decodes the closing sig TLV records in the passed
51+
// ExtraOpaqueData.
52+
func decodeClosingSigs(c *ClosingSigs, tlvRecords ExtraOpaqueData) error {
53+
sig1 := tlv.ZeroRecordT[tlv.TlvType1, Sig]()
54+
sig2 := tlv.ZeroRecordT[tlv.TlvType2, Sig]()
55+
sig3 := tlv.ZeroRecordT[tlv.TlvType3, Sig]()
56+
57+
typeMap, err := tlvRecords.ExtractRecords(&sig1, &sig2, &sig3)
58+
if err != nil {
59+
return err
60+
}
61+
62+
// TODO(roasbeef): helper func to made decode of the optional vals
63+
// easier?
64+
65+
if val, ok := typeMap[c.CloserNoClosee.TlvType()]; ok && val == nil {
66+
c.CloserNoClosee = tlv.SomeRecordT(sig1)
67+
}
68+
if val, ok := typeMap[c.NoCloserClosee.TlvType()]; ok && val == nil {
69+
c.NoCloserClosee = tlv.SomeRecordT(sig2)
70+
}
71+
if val, ok := typeMap[c.CloserAndClosee.TlvType()]; ok && val == nil {
72+
c.CloserAndClosee = tlv.SomeRecordT(sig3)
73+
}
74+
75+
return nil
76+
}
77+
78+
// Decode deserializes a serialized ClosingComplete message stored in the
79+
// passed io.Reader.
80+
func (c *ClosingComplete) Decode(r io.Reader, _ uint32) error {
81+
// First, read out all the fields that are hard coded into the message.
82+
err := ReadElements(r, &c.ChannelID, &c.FeeSatoshis, &c.Sequence)
83+
if err != nil {
84+
return err
85+
}
86+
87+
// With the hard coded messages read, we'll now read out the TLV fields
88+
// of the message.
89+
var tlvRecords ExtraOpaqueData
90+
if err := ReadElements(r, &tlvRecords); err != nil {
91+
return err
92+
}
93+
94+
if err := decodeClosingSigs(&c.ClosingSigs, tlvRecords); err != nil {
95+
return err
96+
}
97+
98+
if len(tlvRecords) != 0 {
99+
c.ExtraData = tlvRecords
100+
}
101+
102+
return nil
103+
}
104+
105+
// closingSigRecords returns the set of records that encode the closing sigs,
106+
// if present.
107+
func closingSigRecords(c *ClosingSigs) []tlv.RecordProducer {
108+
recordProducers := make([]tlv.RecordProducer, 0, 3)
109+
c.CloserNoClosee.WhenSome(func(sig tlv.RecordT[tlv.TlvType1, Sig]) {
110+
recordProducers = append(recordProducers, &sig)
111+
})
112+
c.NoCloserClosee.WhenSome(func(sig tlv.RecordT[tlv.TlvType2, Sig]) {
113+
recordProducers = append(recordProducers, &sig)
114+
})
115+
c.CloserAndClosee.WhenSome(func(sig tlv.RecordT[tlv.TlvType3, Sig]) {
116+
recordProducers = append(recordProducers, &sig)
117+
})
118+
119+
return recordProducers
120+
}
121+
122+
// Encode serializes the target ClosingComplete into the passed io.Writer.
123+
func (c *ClosingComplete) Encode(w *bytes.Buffer, _ uint32) error {
124+
if err := WriteChannelID(w, c.ChannelID); err != nil {
125+
return err
126+
}
127+
128+
if err := WriteSatoshi(w, c.FeeSatoshis); err != nil {
129+
return err
130+
}
131+
132+
if err := WriteUint32(w, c.Sequence); err != nil {
133+
return err
134+
}
135+
136+
recordProducers := closingSigRecords(&c.ClosingSigs)
137+
138+
err := EncodeMessageExtraData(&c.ExtraData, recordProducers...)
139+
if err != nil {
140+
return err
141+
}
142+
143+
return WriteBytes(w, c.ExtraData)
144+
}
145+
146+
// MsgType returns the uint32 code which uniquely identifies this message as a
147+
// ClosingComplete message on the wire.
148+
//
149+
// This is part of the lnwire.Message interface.
150+
func (c *ClosingComplete) MsgType() MessageType {
151+
return MsgClosingComplete
152+
}
153+
154+
// A compile time check to ensure ClosingComplete implements the lnwire.Message
155+
// interface.
156+
var _ Message = (*ClosingComplete)(nil)

lnwire/closing_sig.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package lnwire
2+
3+
import (
4+
"bytes"
5+
"io"
6+
)
7+
8+
// ClosingSig is sent in response to a ClosingComplete message. It carries the
9+
// signatures of the closee to the closer.
10+
type ClosingSig struct {
11+
// ChannelID serves to identify which channel is to be closed.
12+
ChannelID ChannelID
13+
14+
// ClosingSigs houses the 3 possible signatures that can be sent.
15+
ClosingSigs
16+
17+
// ExtraData is the set of data that was appended to this message to
18+
// fill out the full maximum transport message size. These fields can
19+
// be used to specify optional data such as custom TLV fields.
20+
ExtraData ExtraOpaqueData
21+
}
22+
23+
// Decode deserializes a serialized ClosingSig message stored in the passed
24+
// io.Reader.
25+
func (c *ClosingSig) Decode(r io.Reader, _ uint32) error {
26+
// First, read out all the fields that are hard coded into the message.
27+
err := ReadElements(r, &c.ChannelID)
28+
if err != nil {
29+
return err
30+
}
31+
32+
// With the hard coded messages read, we'll now read out the TLV fields
33+
// of the message.
34+
var tlvRecords ExtraOpaqueData
35+
if err := ReadElements(r, &tlvRecords); err != nil {
36+
return err
37+
}
38+
39+
if err := decodeClosingSigs(&c.ClosingSigs, tlvRecords); err != nil {
40+
return err
41+
}
42+
43+
if len(tlvRecords) != 0 {
44+
c.ExtraData = tlvRecords
45+
}
46+
47+
return nil
48+
}
49+
50+
// Encode serializes the target ClosingSig into the passed io.Writer.
51+
func (c *ClosingSig) Encode(w *bytes.Buffer, _ uint32) error {
52+
if err := WriteChannelID(w, c.ChannelID); err != nil {
53+
return err
54+
}
55+
56+
recordProducers := closingSigRecords(&c.ClosingSigs)
57+
58+
err := EncodeMessageExtraData(&c.ExtraData, recordProducers...)
59+
if err != nil {
60+
return err
61+
}
62+
63+
return WriteBytes(w, c.ExtraData)
64+
}
65+
66+
// MsgType returns the uint32 code which uniquely identifies this message as a
67+
// ClosingSig message on the wire.
68+
//
69+
// This is part of the lnwire.Message interface.
70+
func (c *ClosingSig) MsgType() MessageType {
71+
return MsgClosingSig
72+
}
73+
74+
// A compile time check to ensure ClosingSig implements the lnwire.Message
75+
// interface.
76+
var _ Message = (*ClosingSig)(nil)

lnwire/fuzz_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,3 +878,25 @@ func FuzzInvalidOnionPayload(f *testing.F) {
878878
onionFailureHarness(t, data, CodeInvalidOnionPayload)
879879
})
880880
}
881+
882+
func FuzzClosingSig(f *testing.F) {
883+
f.Fuzz(func(t *testing.T, data []byte) {
884+
// Prefix with ClosingSig.
885+
data = prefixWithMsgType(data, MsgClosingSig)
886+
887+
// Pass the message into our general fuzz harness for wire
888+
// messages!
889+
harness(t, data)
890+
})
891+
}
892+
893+
func FuzzClosingComplete(f *testing.F) {
894+
f.Fuzz(func(t *testing.T, data []byte) {
895+
// Prefix with ClosingComplete.
896+
data = prefixWithMsgType(data, MsgClosingComplete)
897+
898+
// Pass the message into our general fuzz harness for wire
899+
// messages!
900+
harness(t, data)
901+
})
902+
}

0 commit comments

Comments
 (0)